Vulnerability DatabaseGHSA-7gf8-v4c4-pph7

GHSA-7gf8-v4c4-pph7: 
JavaScript vulnerability analysis and mitigation

Summary

RE2.prototype.split (and String.prototype.split with an RE2 separator) runs in O(n²) time when the leftmost match is zero-width and lies ahead of the cursor. This happens with \b and \B, and with ^/$ under the m flag. Each such match makes the loop emit the single character at the cursor, step forward one character, and search again from there, which finds the same distant match again. A 200,000-character subject (~600 KB of ordinary CJK text) blocks the event loop for about 81 seconds. The built-in engine takes 1 ms. The output is also wrong: one piece per character instead of one piece per boundary. This is the same empty-match iteration family as CVE-2026-68499 (GHSA-6hxr-mr5r-9836). That advisory named split's empty-match guard as the safe model for its fix, but that guard is the root cause here.

Details

Root cause

// lib/split.cc (1.27.0), WrappedRE2::Split
while (byteIndex < str.size && re2->regexp.Match(str, byteIndex, str.size, RE2::UNANCHORED, &groups[0], groups.size()))
{
        if (match.size()) { /* split at the match */ }
        else
        {
                // zero-width match: push ONE character at byteIndex, advance ONE character,
                // regardless of where the match actually is
                size_t sym_size = getUtf8CharSize(str.data[byteIndex], str.size - byteIndex);
                pieces.push_back(re2::StringPiece(str.data + byteIndex, sym_size));
                byteIndex += sym_size;
        }
}

When the empty match is at position m > byteIndex, the match position is ignored. Every iteration rescans [byteIndex, m], so a subject of n characters with one boundary at the end costs about n²/2 character steps. RE2's \b is ASCII-only, so any run of non-ASCII text (Chinese, Japanese, Cyrillic, emoji), whitespace or punctuation is a run with no boundary inside it.

Proof of concept

const RE2 = require('re2');                       // 1.27.0
const s = '中文文本测试内容'.repeat(25000) + 'a';    // 200,001 chars
console.time('re2');    s.split(new RE2('\\b'));  console.timeEnd('re2');     // ~81 s
console.time('native'); s.split(/\b/u);           console.timeEnd('native');  // ~1 ms
'  a'.split(new RE2('\\b'));     // [" ", " ", "a"]   native: ["  ", "a"]
'abc'.split(new RE2('$', 'm'));  // ["a", "b", "c"]   native: ["abc"]

Measured on a clean npm install re2@1.27.0 (stock prebuilt, Node 26, x86-64 Linux):

subject (CJK + "a")re2 1.27.0built-in
25,000 chars1.3 s0 ms
50,0005.0 s0 ms
100,00020.4 s0 ms
200,00080.9 s1 ms
Time grows 4× per doubling. Other triggers: ' '.repeat(200000) + 'a' with \b (26.7 s), and 'x'.repeat(100000) + '\n' with new RE2('^', 'm') (6.9 s).
<img width="1122" height="173" alt="image" src="https://github.com/user-attachments/assets/33c6a797-11e8-4b5e-bd8f-56de1670db69" />

Impact

Denial of service. The call is synchronous native code, so it blocks the whole event loop, and nothing in JS (a timer, try/catch) can interrupt it. The pattern is usually fixed by the developer, so the only precondition is that an application splits attacker-controlled text with \b, \B or a multiline anchor. split(/\b/) is a common way to tokenize words, and the trigger is any long run of non-ASCII text, which is ordinary input for non-English users. A single request of about 1 MB costs minutes of CPU, and repeated requests keep a worker blocked. Bounded per request: unlike CVE-2026-68499 it terminates, and memory stays linear. Implement ECMAScript SplitMatcher semantics. Keep p (end of the last split) and q (search start) separate. Use each match at its real position. When an empty match is at p, or any match is at the very end, advance q by one code point instead of splitting. q never moves backwards, so the loop is linear. Patch: q3_split_quadratic.patch (applies to 1.27.0; the 1.27.0 test suite passes). It also fixes the output: split(/\b/), ^/$ (m), (a)? and (a)| now match the built-in engine.

size_t p = 0, q = 0;
while (q < str.size && re2->regexp.Match(str, q, str.size, RE2::UNANCHORED, &groups[0], groups.size()))
{
        size_t m = match.data() - str.data, e = m + match.size();
        if (m >= str.size) break;                                                    // a match at the end never splits
        if (e == p) { q = m + getUtf8CharSize(str.data[m], str.size - m); continue; } // empty match at p
        pieces.push_back(re2::StringPiece(str.data + p, m - p));
        if (pieces.size() >= limit) break;
        pieces.insert(pieces.end(), groups.begin() + 1, groups.end());
        if (pieces.size() >= limit) break;
        p = q = e;
}
if (str.size && pieces.size() < limit) pieces.push_back(re2::StringPiece(str.data + p, str.size - p));

Workaround: don't split untrusted text with \b, \B or multiline anchors. Use matchAll with a consuming pattern such as /\w+|\W+/g instead.


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