Skip to main content

node-re2 CVE-2026-71430

| EUVDEUVD-2026-54159 MEDIUM
Reachable Assertion (CWE-617)
2026-08-06 https://github.com/uhop/node-re2 GHSA-8hcv-x26h-mcgp
6.2
CVSS 3.1 · Vendor: https://github.com/uhop/node-re2
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Craft string of 40,000+ identical chars
  2. Delivery
    Submit to service endpoint using re2 global replace
  3. Exploit
    O(input²) result exceeds V8 max string length
  4. Execution
    ToLocalChecked() invoked on empty MaybeLocal
  5. Persist
    Native abort() fires (SIGABRT)
  6. Impact
    Node.js process terminates, all requests dropped

Vulnerability Assessment

Weakness
CWE
ASVS 5.0
V16 - Security Logging and Error Handling Reachable assertion handling
Exploitation Conditions

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'). (2) The replacement template string contains $' (text after the match) or ` $ ` (text before the match) - the $& template, numeric group references, and literal (non-special) replacement strings do NOT trigger amplification and are safe. (3) The input string is large enough that the O(input²) amplified output exceeds V8's ~536,870,888-character ceiling - empirically, ~40,000 single-character matches (threshold between 30,000 safe and 40,000 crashing). What limits exploitation: the developer must have deliberately used $' or $ ` as a replacement template (non-default; these are specialized back-references rarely needed); applications using only literal, $&, or numbered-group templates are completely unaffected. Non-global replaces (no 'g'` flag) produce O(1) output and are also unaffected. On 32-bit platforms the V8 string ceiling is lower (~268M chars), meaning the threshold would be reached at a smaller input, but this is an uncommon deployment for Node.js services.

Impact

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. AV:L (local access) underrepresents the realistic threat model: any Internet-facing Node.js service that feeds user-supplied strings into re2.replace with a $' or ` $ ` template is remotely exploitable at network speed. The real-world risk is elevated beyond the 6.2 score for two reasons: (1) the crash is uncatchable and kills the entire process - a single HTTP request can take down all concurrent users - and (2) the package is specifically chosen by security-conscious developers to safely handle untrusted regex input, meaning the audience is disproportionately services that do process attacker-controlled content. No EPSS score was provided; no CISA KEV listing exists, indicating exploitation is not yet confirmed as widespread. A working POC is publicly available in the GHSA advisory, lowering the bar to exploitation. The AC:L assessment is accurate: no special conditions are needed beyond the standard trigger. The primary limiting factor is whether the application developer chose $' or $ ` templates - if a service uses only constant or $&` templates, it is not affected. SSVC signals: exploitation is possible (POC public), attack is automatable (single HTTP request), technical impact is total loss of availability for the process.

Exploit ScenarioDerived

An attacker sends a POST request to a content-processing API endpoint where the backend calls re2.replace(input, new RE2('a', 'g'), "$'") on the attacker-supplied body. By submitting a body of 40,000 or more identical characters (e.g., 'a'.repeat(40000)), the replacement output grows to approximately 800 million characters, exceeding V8's string limit. The Node.js process receives SIGABRT and exits with code 134, dropping all concurrent connections. A public POC demonstrating this exact behavior on Node v24 with re2@1.24.1 is included in the GHSA advisory.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.1% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Aug 06, 2026

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). Unlike the built-in regex engine, which raises a catchable RangeError, this crash cannot be intercepted by JavaScript try/catch, domains, or uncaughtException` handlers, making a single malformed request capable of taking down the entire service. A public proof-of-concept is included in the GitHub Security Advisory; no CISA KEV listing was present at time of analysis.

RemediationAI

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. The upgrade is non-breaking and requires no API changes: npm install re2@>=1.25.1 or npm upgrade re2 in any project using node-re2 is sufficient. If an immediate upgrade is not feasible, two compensating controls apply with meaningful trade-offs: (1) Audit all call sites for re2.replace with global flags and replace $' or ` $ ` templates with $&` or literal strings - this eliminates the amplification path but may require logic changes if post/pre-match capture was intentional; (2) Enforce application-layer input length limits (e.g., reject strings exceeding 30,000 characters before they reach the replace path) - this prevents the threshold from being reached but requires accurate knowledge of all entry points and does not fix the underlying defect. The vendor advisory is at https://github.com/uhop/node-re2/security/advisories/GHSA-8hcv-x26h-mcgp.

Affected VersionsENISA

node-re2 < 1.25.1

Affected Packages

npm re2 fix: 1.25.1
euvd node_re2 fix: 1.25.1

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 2 packages in npm, euvd

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

node-re2 (CPE: pkg:npm/re2) is a Node.js native add-on wrapping Google's RE2 library via the Nan (Native Abstractions for Node.js) C++ bridge. The vulnerability is in lib/replace.cc at the point where the computed replacement string is returned to V8. V8 imposes a hard maximum string length (~536,870,888 characters on 64-bit platforms), and when Nan::New(result) is called with a string exceeding this limit, it returns an empty MaybeLocal<v8::String> to signal failure. The Nan convention is to check .IsEmpty() before calling .ToLocalChecked(); skipping this check and calling .ToLocalChecked() on an empty MaybeLocal invokes v8::Utils::ReportApiFailure which unconditionally calls abort(). CWE-617 (Reachable Assertion) captures this class: a runtime invariant assumed by the code is violated, and the failure path is a process-terminating trap rather than a graceful error. The amplification arises from $' and ` $ ` back-references: $' appends the entire post-match suffix to each replacement slot, so on a string of N identical characters with a global single-char pattern, the aggregate output approaches N²/2 characters. At N≈40,000 this surpasses V8's ceiling. $&`, literal, and numbered group templates produce O(N) output and are unaffected.

Know when Node.js gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/uhop/node-re2) PRIMARY 6.2 MEDIUM
AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
vuln.today AI 7.5 HIGH

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.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Red Hat 7.5 HIGH

Primary rating from Vendor (https://github.com/uhop/node-re2).

CVSS VectorVendor: https://github.com/uhop/node-re2

Attack Vector
Local
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

Lifecycle Timeline

1
Patch available
Aug 06, 2026 - 23:03 EUVD

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):

cpp
// 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
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:

cpp
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.

Blast Radius

ecosystem impact
† from your stack dependencies † transitive graph · vuln.today resolves 4-path depth
  • 1 npm packages depend on re2 (1 direct, 0 indirect)

Ecosystem-wide dependent count for version 1.25.1.

Threat Intelligence Overview

EPSS Score
0.1%
Top 99% exploitable
Prevalence
Medium
popular Node.js npm package for safe untrusted-input regex
Threat Intel
1
1 sources
Exploit
POC
Public exploit code exists
Data Quality
7 sources
Confidence: High
EUVD NVD CVE.org EPSS Vulnrichment GHSA Vendor GitHub VulDB

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC Yes
EPSS 0.1%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation
Poc
System Exposure· derived
Small
Automatable
No
Human Impact· derived
Medium
Technical Impact
Partial

Priority Score

51
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +31
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.

CVE-2025-68613 HIGH POC
8.8 Dec 19

Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation

CVE-2024-41713 CRITICAL POC
9.1 Oct 21

A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could

CVE-2024-55591 CRITICAL POC
9.8 Jan 14

FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote

CVE-2023-44487 HIGH POC
7.5 Oct 10

Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour

CVE-2014-7205 CRITICAL POC
10.0 Oct 08

Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t

CVE-2025-59528 CRITICAL POC
10.0 Sep 22

Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete

CVE-2017-14849 HIGH POC
7.5 Sep 28

Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc

CVE-2017-5941 CRITICAL POC
9.8 Feb 09

An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2014-3744 HIGH POC
7.5 Oct 23

Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi

CVE-2014-9566 HIGH POC
7.5 Mar 10

Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin

CVE-2013-4660 MEDIUM POC
6.8 Jun 28

The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic

Vendor StatusVendor

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy