Vulnerability DatabaseGHSA-x77q-8rq8-rq6v

GHSA-x77q-8rq8-rq6v: 
JavaScript vulnerability analysis and mitigation

Summary

CVE-2026-71430 (GHSA-8hcv-x26h-mcgp) fixed an abort when a global replace with $' or $` produced a result longer than V8's maximum string length. The fix added an IsEmpty() check on the finished result. But WrappedRE2::Replace first builds that result in a native std::string with no size limit. The quadratic output is therefore still allocated in full, which takes gigabytes for a subject of a few dozen KB. The addon is built with -fno-exceptions, so a failed allocation throws std::bad_alloc, nothing catches it, and std::terminate aborts the process (SIGABRT, exit 134). Under a container memory limit the kernel OOM-kills the process before the final check is ever reached.

Details

Measured on re2@1.27.0 (published prebuilt), Node 26.13, Linux x64:

InputMemory limitbuilt-in RegExpre2 1.27.0
40,000 chars (the original advisory's PoC)ulimit -v 1.5 GBRangeError, 9 ms, peak 52 MBstd::bad_alloc → SIGABRT (134)
40,000 charsnoneRangeError, 7 msRangeError after 3.1 s, peak 1.6 GB
120,000 charsulimit -v 6 GBRangeErrorstd::bad_alloc → SIGABRT (134)
Buffer subject, 120,000 bytesulimit -v 3 GBn/astd::bad_alloc → SIGABRT (134). For Buffers the final check is node::Buffer::kMaxLength (2^53), so no size is rejected before the allocation.

Proof of concept

const RE2 = require('re2');
const s = 'a'.repeat(Number(process.argv[2] || 40000));
try { s.replace(/a/g, "$'"); } catch (e) { console.log('native:', e.message); }   // RangeError, ~9 ms, ~50 MB
try { s.replace(new RE2('a', 'g'), "$'"); } catch (e) { console.log('re2:', e.message); }

<img width="1442" height="147" alt="image" src="https://github.com/user-attachments/assets/c3e2f277-bf32-417c-9ad4-9f131581954e" />

Impact

Same as CVE-2026-71430. Any service where the replacement template (containing $' or $`) or the subject size is attacker-influenced can be crashed with one small request; user-facing search-and-replace with untrusted patterns is a typical case. The abort can't be caught, and in memory-limited containers the original advisory's own PoC still kills the process.

Suggested Fix

  • The template path runs a size-only dry pass (a SizeSink through the same template code) whenever a cheap worst-case bound (n + (n+1)·(len + count('$')·n)) could exceed the limit. It throws a catchable RangeError before allocating, then reserves exactly. Small inputs skip the extra pass.
  • The function-replacer path checks a running byte budget after each part.
  • Buffer results use the same cap as strings (v8::String::kMaxLength).
  • Unrelated hardening in the same area: prepareArgument now throws instead of aborting when the subject's UTF-8 buffer can't be allocated.

Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-x77q-8rq8-rq6vMEDIUM6.2
  • JavaScript logoJavaScript
  • re2
NoYesNov 08, 2026
GHSA-7gf8-v4c4-pph7MEDIUM6.2
  • JavaScript logoJavaScript
  • re2
NoYesNov 08, 2026
GHSA-m9gh-5x7v-rqj2HIGHN/A
  • JavaScript logoJavaScript
  • @devilsdev/rag-pipeline-utils
NoYesNov 08, 2026
GHSA-89fq-598q-39wcMEDIUMN/A
  • JavaScript logoJavaScript
  • @devilsdev/rag-pipeline-utils
NoYesNov 08, 2026
GHSA-4jh4-qv86-j2gwMEDIUMN/A
  • JavaScript logoJavaScript
  • @devilsdev/rag-core
NoYesNov 08, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management