Nodejs re2 Package, Out-of-Bounds Heap Read, CVE-2026-67550 (Moderate) -DC-Jul2026-1175

Listen to this Post

The `re2` npm package provides Node.js bindings for Google’s RE2 regular expression engine. Prior to version 1.25.2, the library contained a critical flaw in its handling of the user-settable `lastIndex` property on global or sticky regex instances.
The root cause lies in a type confusion between UTF-8 byte length and UTF-16 code-unit count. When a subject string is prepared, the `StrVal` wrapper stores the subject’s UTF-8 byte length in `StrVal::length` (via `utf8Length` at lib/addon.cc:200). The `setIndex` method then validates the provided `lastIndex` against this byte length. However, the subsequent buffer walk uses `lastIndex` as a UTF-16 code-unit offset, not a byte offset, and performs no bounds checking.
For any non-ASCII subject, the UTF-8 byte length is always greater than the true UTF-16 character count. An attacker can set `lastIndex` to a value between these two lengths, passing the validation check while pointing past the end of the allocated buffer. The `getUtf16PositionByCounter` function then reads `data

` and advances by the UTF-8 character size without verifying `from` against the buffer size. This results in an out-of-bounds heap read.
With a sufficiently large subject, the read operation marches into unmapped memory, causing the process to terminate with SIGABRT or SIGSEGV. This is an uncatchable native crash — `try/catch` blocks in JavaScript cannot prevent termination — leading to a denial of service for any Node.js worker or process that executes the match. In some limited cases, adjacent heap bytes may be copied into the returned value, resulting in a bounded, best-effort information disclosure.
The vulnerability is reachable through <code>exec</code>, <code>test</code>, <code>String.prototype.match</code>, <code>replace</code>, and `split` on any global or sticky RE2 instance. It is triggered solely on non-ASCII subjects; ASCII subjects are unaffected because their byte length equals their UTF-16 length. This issue is distinct from the previously fixed GHSA-8hcv-x26h-mcgp (global `replace()` output-amplification abort) and remains present in version 1.25.1.
The fix, implemented in version 1.25.2, validates `lastIndex` against the subject's true UTF-16 length and adds bounds checking to the buffer walk. Users are strongly advised to upgrade immediately or, as a workaround, clamp `lastIndex` to `str.length` for non-ASCII subjects.

<h2 style="color: blue;">DailyCVE Form:</h2>

Platform: Node.js re2
Version: < 1.25.2
Vulnerability: OOB heap read
Severity: Moderate
date: 2026-07-30

<h2 style="color: blue;">Prediction: 2026-07-07</h2>

<h2 style="color: blue;">What Undercode Say:</h2>

<h2 style="color: blue;">Analytics:</h2>

<ul>
<li>Affected methods: <code>exec</code>, <code>test</code>, <code>match</code>, <code>replace</code>, `split`
- Trigger condition: `lastIndex` between UTF-8 byte length and UTF-16 length on non-ASCII subject</li>
<li>Crash type: SIGABRT/SIGSEGV (uncatchable)</li>
<li>Fixed in: `[email protected]`
</li>
</ul>

<h2 style="color: blue;">Bash commands and codes:</h2>

[bash]
Check installed version
npm list re2
Upgrade to patched version
npm install [email protected]
Verify upgrade
npm list re2

Proof of concept (ASAN):

const RE2 = require('re2');
const re = new RE2('a', 'y');
re.lastIndex = 3; // 3 <= byteLen(4) passes guard; only 2 real chars
re.exec('éé'); // U+00E9 = 2 bytes each → OOB read

Real-world crash (large subject):

const RE2 = require('re2');
const s = '中'.repeat(40000000); // UTF-16 40M, UTF-8 120M
const re = new RE2('a', 'y');
re.lastIndex = Buffer.byteLength(s) - 1; // passes byte-length guard
re.exec(s); // SIGSEGV (exit 139)

Exploit:

An attacker can trigger the vulnerability by:

  1. Identifying a Node.js application that uses a global or sticky `RE2` instance on user-supplied non-ASCII input.
  2. Setting `lastIndex` to a value greater than the string’s UTF-16 length but less than or equal to its UTF-8 byte length.
  3. Invoking any of the affected methods (exec, test, match, replace, split).
  4. Causing the Node.js process to crash with an uncatchable native fault.
    The exploit requires no authentication and can be performed remotely wherever the application accepts attacker-influenced `lastIndex` values (e.g., resuming a scan or pagination from a client-supplied offset). The crash terminates the entire worker/process, enabling denial-of-service attacks.

Protection:

  • Immediate: Upgrade to `[email protected]` or later.
  • Workaround (if unable to upgrade): Never assign `lastIndex` from untrusted input. For non-ASCII subjects, clamp `lastIndex` to the subject’s true string length (str.length) before calling any affected method.
  • Defense in depth: Validate and sanitize all user-supplied offsets before using them with `RE2` instances. Consider using ASCII-only subjects where possible, as the vulnerability does not affect them.

Impact:

  • Denial of Service (Primary): An uncatchable native crash that terminates the Node.js process or worker. Remotely exploitable without authentication.
  • Information Disclosure (Secondary, Best-Effort): Out-of-bounds heap bytes may be copied into returned values (e.g., leading segment of a `replace` result). This is bounded and unreliable due to calloc-allocated zero-filled buffers and the variable over-read distance.

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top