Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.
Open advisories
4 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.
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 buffer. In replace() and split() those bytes are copied into the returned Buffer, disclosing adjacent heap memory to JavaScript. The trigger is deterministic and requires no special heap grooming. Only Buffer input is affected. String input was never at risk: re-encoding guarantees every multi-byte sequence is complete. Root cause getUtf8CharSize maps a lead byte to a length of 1–4 and never sees the input size: Callers then read that many bytes. In the zero-width branch of replace(), the guard proves only that at least one byte remains: offset < size permits offset == size - 1, so a lead…
Recommended action: Upgrade to 1.26.1 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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): When a global replace uses an output-amplifying template — $' (text after the match) or $ (text before the match) — the result grows to O(input²). For an input of ~40,000+ identical single-char matches the result exceeds V8's String::kMaxLength (~536,870,888 chars on 64-bit). Nan::New(result) then returns an empty MaybeLocal, and the unchecked .ToLocalChecked() calls v8::Utils::ReportApiFailure → FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal → abort() (SIGABRT). This is an uncatchable crash: it is not a JavaScript exception, so a surrounding try/catch cannot stop it — the entire Node process (or worker) dies. The built-in regex engine handles the identical case correctly by throwing a catchable RangeError: Invalid string length. node-re2 diverges…
Recommended action: Upgrade to 1.25.1 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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 subject the read marches into unmapped memory and the process dies with SIGABRT/SIGSEGV — an uncatchable crash (try/catch cannot stop it), i.e. a denial of service for any worker/process that runs the match. In some cases the out-of-bounds bytes are copied into the returned value (a bounded, best-effort heap information leak). Root cause The subject wrapper stores the UTF-8 byte length in StrVal::length: - lib/addon.cc:200 auto argLength = utf8Length(s, isolate); — UTF-8 byte count - lib/addon.cc:209 lastStringValue.reset(buffer, argSize, argLength, startFrom, false,…
Recommended action: Upgrade to 1.25.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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 call is synchronous native code, so it blocks the entire event loop and cannot be interrupted by try/catch, AbortController, --max-old-space-size, or timers — the process must be killed externally. This diverges from the built-in engine, where 'xxxx'.match(/a/g) returns a finite array. Root cause When match.size() == 0, byteIndex is unchanged, so the next iteration matches the same empty position again; groups grows without bound. The other iteration paths already guard this: lib/split.cc:50-55 advances by getUtf8CharSize on an empty match, and exec advances…
Recommended action: Upgrade to 1.25.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.