Know every vulnerabilitybefore it knows you.
DevGuard continuously monitors your dependencies and alerts you when CVEs like this one affect your stack — with real-time threat intelligence built for developers.
GHSA-8hcv-x26h-mcgp
No affected components available
Description
WrappedRE2::Replace builds the replacement result and hands it to V8 with .ToLocalChecked() without checking for the empty MaybeLocal that V8 returns when the string/buffer exceeds its maximum length:
lib/replace.cc (v1.24.1):
// L553 — Buffer return path
info.GetReturnValue().Set(Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked());
// L556 — String return path
info.GetReturnValue().Set(Nan::New(result).ToLocalChecked());
When a global replace uses an output-amplifying template — $' (text after the match) or $` (text before the match) — the result grows to O(input²). For an input of ~40,000+ identical single-char matches the result exceeds V8's String::kMaxLength (~536,870,888 chars on 64-bit). Nan::New(result) then returns an empty MaybeLocal, and the unchecked .ToLocalChecked() calls v8::Utils::ReportApiFailure → FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal → abort() (SIGABRT).
This is an uncatchable crash: it is not a JavaScript exception, so a surrounding try/catch cannot stop it — the entire Node process (or worker) dies.
The built-in regex engine handles the identical case correctly by throwing a catchable RangeError: Invalid string length. node-re2 diverges from that contract and aborts instead.
Proof of concept
npm i re2
node poc.js
const RE2 = require('re2');
// Built-in engine: same case -> CATCHABLE RangeError (correct)
try { 'a'.repeat(50000).replace(/a/g, "$'"); }
catch (e) { console.log('native:', e.constructor.name, e.message); } // RangeError: Invalid string length
// re2: ABORTS the whole process (uncatchable; try/catch does not help)
'a'.repeat(50000).replace(new RE2('a', 'g'), "$'");
// -> FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal (process exits 134 / SIGABRT)
Observed (Node v24, clean npm i re2 → re2@1.24.1): native branch prints RangeError: Invalid string length; the re2 branch aborts with FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal, stack top WrappedRE2::Replace, process exit code 134.
Threshold matches the mechanism precisely: input of 30,000 chars completes; 40,000 aborts (30000²/2 ≈ 4.5e8 < 5.37e8 max; 40000²/2 ≈ 8e8 > max). $&/constant templates and non-global replaces do not amplify and do not crash.
Impact
A remote, unauthenticated denial of service against any service that runs String.prototype.replace / the re2 [Symbol.replace] path where either the replacement template (containing $' or $`) or the input size is attacker-influenced. Because the failure is a native abort(), it cannot be contained by try/catch or domains — one request takes down the whole process/worker. This is especially impactful for re2's core audience, who adopt it specifically to process untrusted patterns/inputs safely.
Suggested fix
Check the MaybeLocal before ToLocalChecked on both return paths (and the intermediate group-string builds), and throw a catchable RangeError to match the built-in engine:
auto maybe = Nan::New(result);
if (maybe.IsEmpty()) { Nan::ThrowRangeError("Invalid string length"); return; }
info.GetReturnValue().Set(maybe.ToLocalChecked());
(Apply equivalently to the Nan::CopyBuffer(...) buffer path at L553 and to the per-group Nan::New(data, size).ToLocalChecked() sites used by the replacer-function path.)
Resolution
Resolved in re2 1.25.1. WrappedRE2::Replace now checks the returned MaybeLocal on every result path and throws a catchable RangeError: Invalid string length (matching the built-in engine) instead of aborting the process with an uncatchable SIGABRT. No API changes --- upgrade to re2 >= 1.25.1 via a plain npm upgrade to receive the fix.
The vulnerability requires local access to the device to be exploited. It is easy for an attacker to exploit this vulnerability. An attacker does not need any special privileges or access rights. No user interaction is needed for the attacker to exploit this vulnerability. The impact is confined to the system where the vulnerability exists. There is a high impact on the availability of the system.
Exploitation attempts have been detected. Elevated vigilance and prompt remediation are advised.
The exploit probability is very low. The vulnerability is unlikely to be exploited in the next 30 days.
We did not find any exploit available. Neither in GitHub repositories nor in the Exploit-Database.
Browse More
Continuously monitor your dependencies and get alerted when vulnerabilities like this one affect your stack.
Checkout DevGuard