Severity by source
AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
AV:N because the advisory explicitly confirms remote unauthenticated exploitation via network input; the provided AV:L conflicts with this and appears to be a scoring error.
Primary rating from Vendor (https://github.com/uhop/node-re2).
CVSS VectorVendor: https://github.com/uhop/node-re2
Lifecycle Timeline
3Blast Radius
ecosystem impact- 1 npm packages depend on re2 (1 direct, 0 indirect)
Ecosystem-wide dependent count for version 1.25.1.
DescriptionCVE.org
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.jsconst 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.
AnalysisAI
Process-terminating denial of service in node-re2 (npm package re2) up to and including v1.25.0 allows an attacker to kill the entire Node.js process or worker thread with a single crafted request. The native add-on's WrappedRE2::Replace calls .ToLocalChecked() on a V8 MaybeLocal without first verifying it is non-empty; when a global replace uses the $' (post-match) or $ (pre-match) template on ~40,000+ matching characters, the O(input²) output exceeds V8's 536,870,888-character limit, the MaybeLocal is empty, and the unchecked call triggers v8::Utils::ReportApiFailure → native abort() (SIGABRT, exit 134). …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | Three conditions must all hold simultaneously: (1) The application uses the `re2` npm package (not the built-in JavaScript `RegExp` engine) and invokes `String.prototype.replace` or the `re2` `[Symbol.replace]` method with the global flag (`'g'`). … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | The provided CVSS vector (AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H, score 6.2) conflicts directly with the advisory description, which explicitly states 'a remote, unauthenticated denial of service against any service' where attacker-controlled input reaches the replace path. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | Full exploit scenario with step-by-step reproduction available after sign-in. |
| Remediation | Upgrade the `re2` npm package to version 1.25.1 or later, which resolves the issue by checking the `MaybeLocal` return value on all result paths in `WrappedRE2::Replace` (both the buffer path at L553 and the string path at L556) and throwing a catchable `RangeError: Invalid string length` instead of aborting - matching the behavior of the built-in engine. … Detailed patch versions, workarounds, and compensating controls in full report. |
Threat intelligence, references, and detailed analysis are available after sign-in.
A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
Same weakness CWE-617 – Reachable Assertion
View allSame technique Denial Of Service
View allVendor StatusVendor
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-54159
GHSA-8hcv-x26h-mcgp