Advisories for Npm/Re2 package

2026

node-re2: String.prototype.replace(re2, template) aborts the Node process (uncatchable ToLocalChecked on empty MaybeLocal) when the result exceeds V8's max string length

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

node-re2: Out-of-bounds heap read in `replace`/`split` via a `Buffer` ending in a truncated multi-byte UTF-8 character → adjacent heap memory disclosed to JavaScript

re2 infers a character's byte length from its UTF-8 lead byte alone, with no bound on the bytes actually remaining in the input. Buffer arguments reach the native layer verbatim — only strings are re-encoded into well-formed UTF-8 — so a Buffer whose last byte is a multi-byte lead promises continuation bytes that are not there, and the result builders read up to 3 bytes past the end of the …

re2: Out-of-bounds heap read in `exec`/`test`/`match` via attacker-influenced `lastIndex` on a non-ASCII subject → uncatchable process crash (DoS)

re2 validates the user-settable lastIndex against the subject's UTF-8 byte length but then uses it as a UTF-16 code-unit count to walk the subject buffer, with no bounds check. For any non-ASCII subject, the byte length is larger than the true character count, so a lastIndex between those two values passes validation while pointing past the end of the buffer. The subsequent walk reads out of bounds. With a large …

re2: Global `String.prototype.match` with an empty-matchable pattern never advances → infinite loop with unbounded native memory growth (DoS)

String.prototype.match with a global RE2 collects all matches in a native loop that advances the cursor by the match length. A zero-width (empty) match has length 0, so the cursor never advances: the same empty match is found forever and appended to an ever-growing native vector. Any pattern that can match the empty string (a*, b?, x{0,3}, (a)|, (?:), …) therefore causes an infinite loop with unbounded memory growth. The …