
PEACH
Un cadre d’isolation des locataires
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.
Measured on re2@1.27.0 (published prebuilt), Node 26.13, Linux x64:
| Input | Memory limit | built-in RegExp | re2 1.27.0 |
|---|---|---|---|
| 40,000 chars (the original advisory's PoC) | ulimit -v 1.5 GB | RangeError, 9 ms, peak 52 MB | std::bad_alloc → SIGABRT (134) |
| 40,000 chars | none | RangeError, 7 ms | RangeError after 3.1 s, peak 1.6 GB |
| 120,000 chars | ulimit -v 6 GB | RangeError | std::bad_alloc → SIGABRT (134) |
Buffer subject, 120,000 bytes | ulimit -v 3 GB | n/a | std::bad_alloc → SIGABRT (134). For Buffers the final check is node::Buffer::kMaxLength (2^53), so no size is rejected before the allocation. |
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" />
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.
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.v8::String::kMaxLength).prepareArgument now throws instead of aborting when the subject's UTF-8 buffer can't be allocated.Source: NVD
Évaluation gratuite des vulnérabilités
É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.
Obtenez une démo personnalisée
"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."