GHSA-7gf8-v4c4-pph7: 
JavaScript Analyse et atténuation de la vulnérabilité

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

Connexe JavaScript Vulnérabilités :

CVE ID

Gravité

Partition

Technologies

Nom du composant

Exploit CISA KEV

A corrigé

Date de publication

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

Évaluation gratuite des vulnérabilités

Évaluez votre posture de sécurité cloud

Évaluez vos pratiques de sécurité cloud dans 9 domaines de sécurité afin d’évaluer votre niveau de risque et d’identifier les lacunes dans vos défenses.

Évaluation de la demande

Ressources Wiz supplémentaires

Obtenez une démo personnalisée

Prêt(e) à voir Wiz en action ?

"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
David EstlickRSSI
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
Adam FletcherChef du service de sécurité
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."
Greg PoniatowskiResponsable de la gestion des menaces et des vulnérabilités