# Regex compiler buffer corruption

Regex compilation or matching writing/reading past buffers sized from a different length than emitted

_Area: Memory corruption and native code. Seen in 2 disclosed reports; one confirmed bounty: $1,500; latest 2019-10-14. Updated 2026-11-02._

## How it works
A regex engine computes a buffer size from one length (pattern length, character count, or a code-point bound) but then emits a different quantity: decoded code points, multi-byte characters, or state values. When the emitted value exceeds the assumed bound, the write or read runs past the allocation. The broken assumption is that "input length" and "output length" are interchangeable, and that a parsed value fits the type it is stored in. Octal escapes above 0xff, UTF-8 multi-byte sequences, and conditional/group constructs all break that assumption [E2](https://bugbountylibrary.com/r/h1%3A237915.md)[E3](https://bugbountylibrary.com/r/h1%3A207983.md)[E1](https://bugbountylibrary.com/r/h1%3A1549636.md).

## Where it shows up
- Escape decoding that stores a parsed numeric value into a byte-sized field (e.g. octal `\700` producing a code point > 0xff) [E2](https://bugbountylibrary.com/r/h1%3A237915.md)
- Char-class and state-transition parsing where next-state values are written without re-checking the bound [E2](https://bugbountylibrary.com/r/h1%3A237915.md)
- Match loops reading multi-byte/UTF-8 characters that can step past the string end by up to a UV-sized amount [E3](https://bugbountylibrary.com/r/h1%3A207983.md)
- Compilation of attacker-controlled pattern strings that allocates and frees intermediate structures (double-free risk) [E1](https://bugbountylibrary.com/r/h1%3A1549636.md)
- Any regex path reachable from untrusted input: mbstring, template engines, validators [E2](https://bugbountylibrary.com/r/h1%3A237915.md)

## How to review
Find every place a buffer is sized from one length and filled from another. The invariant: the emitted count (code points, bytes, state values) must be provably ≤ the allocated capacity, and every parsed numeric value must be range-checked against its storage type before use. For match loops, confirm the read pointer is bounds-checked before each multi-byte fetch, not after. For compilation, trace ownership of intermediate buffers so each allocation is freed exactly once on every error path [E1](https://bugbountylibrary.com/r/h1%3A1549636.md).

## How finders spotted it
- ASan/fuzzing of the interpreter's regex paths surfaced an out-of-bounds read in S_regmatch during substitution, showing the match loop over-reads past the buffer end [E3](https://bugbountylibrary.com/r/h1%3A207983.md).
- Reading the escape-decoding path revealed octal values above 0xff were not handled, producing an invalid code point written out of bounds [E2](https://bugbountylibrary.com/r/h1%3A237915.md).
- Recognizing that regex compilation of attacker-controlled source is a memory-safety surface, and that malformed conditional/group constructs stress free paths [E1](https://bugbountylibrary.com/r/h1%3A1549636.md).

## Variants seen
- Out-of-bounds write from an over-large decoded code point in state handling [E2](https://bugbountylibrary.com/r/h1%3A237915.md)
- Out-of-bounds heap read in the match loop, up to 12 bytes past the buffer depending on encoding [E3](https://bugbountylibrary.com/r/h1%3A207983.md)
- Double free during compilation of a crafted pattern [E1](https://bugbountylibrary.com/r/h1%3A1549636.md)

## Impact and severity
Heap/stack corruption and DoS from malformed patterns [E2](https://bugbountylibrary.com/r/h1%3A237915.md); out-of-bounds read leaking bytes past the buffer [E3](https://bugbountylibrary.com/r/h1%3A207983.md); double free potentially escalated to RCE when chained with marshal.load [E1](https://bugbountylibrary.com/r/h1%3A1549636.md). Severity rises when the engine is reachable from remote untrusted input (PHP mbstring) [E2](https://bugbountylibrary.com/r/h1%3A237915.md) and when a second weakness turns corruption into code execution [E1](https://bugbountylibrary.com/r/h1%3A1549636.md).

## Seen in real software
Open-source packages and projects, and products, where this pattern was found. If the target runs one, compare the version it runs with the fix.
- **PHP**: PHP mbstring / Oniguruma multiple remote heap/stack corruptions (CVE-2017-9224, CVE-2017-9226). Report: https://bugbountylibrary.com/r/h1%3A237915.md. Fix: https://github.com/php/php-src/commit/20eacb787f4543604f3c657e191baf274bb943c2
- **Perl**: read outside of buffer (heap buffer overflow) in S_regmatch - regexec.c:6057. Report: https://bugbountylibrary.com/r/h1%3A207983.md

## Evidence
- E1: https://bugbountylibrary.com/r/h1%3A1549636.md
- E2: https://bugbountylibrary.com/r/h1%3A237915.md
- E3: https://bugbountylibrary.com/r/h1%3A207983.md
