# Signed length underflow before allocation

Untrusted length decoded to signed int, then negated, subtracted, or multiplied before the size check

_Area: Memory corruption and native code. Seen in 4 disclosed reports; one confirmed bounty: $31,337; latest 2026-10-16. Updated 2026-10-31._

## How it works
A length or count from untrusted input is decoded into a signed integer, or an unsigned one is used in a subtraction. The code then negates it, adds it to a position, or multiplies it by a repeat bound. The arithmetic wraps or goes negative, so the value reaching the size check or allocation differs from what the attacker supplied. The check was written for the positive case and passes, while the buffer is sized or advanced by a small or negative amount and the real length is used for the read or write.

## Where it shows up
- Varint or format-width length decoded into `int`/`Int32` with only a `length < 0` check or only an upper-bound check [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-86wm-r4c5-2rc9.md)[E4](https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md)
- Bounds written as subtraction: `len > PAGE_SIZE - 2 - size` where `size` can approach the limit [E2](https://bugbountylibrary.com/r/blog%3Awillsroot-io-2022-01-cve-2022-0185-html.md)
- `pos + length` computed before comparing against a limit; INT_MAX wraps negative [E4](https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md)
- Repeat count times body length multiplied in signed int for a size limit [E1](https://bugbountylibrary.com/r/blog%3Arapid7-com-blog-post-ra-gitlab-ci-cd-regex-integer-overflow-technical-analysis-cve-2026-97229.md)

## How to review
Find every length that crosses from parsed input to allocation, offset, or loop bound. The invariant: after decoding, the length must be validated as non-negative AND the sum `pos + length` (and any product with a repeat count) must be computed in a type or with a check that cannot wrap, before any pointer moves or buffer is sized. Confirm the check rejects boundary values (INT_MAX, limit-1), not just negatives. For subtraction bounds, verify the subtrahend is provably below the minuend. For regex or format expansion, verify the size check uses a non-wrapping type. State the signedness explicitly: an unsigned subtraction underflows to a huge value, while a signed sum wraps to a negative one; both bypass a positive-only guard.

## Variants seen
- Unsigned subtraction underflow in a kernel bound check, unbounded heap overflow [E2](https://bugbountylibrary.com/r/blog%3Awillsroot-io-2022-01-cve-2022-0185-html.md)
- Negative varint length passed to a Foundation `Data` initializer, trapping the process [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-86wm-r4c5-2rc9.md)
- Positive INT_MAX length overflowing `pos + length` past an upper-bound guard [E4](https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md)
- Signed multiplication of body length by repeat bound overflowing a size limit [E1](https://bugbountylibrary.com/r/blog%3Arapid7-com-blog-post-ra-gitlab-ci-cd-regex-integer-overflow-technical-analysis-cve-2026-97229.md)

## Why fixes fail
E4 is an incomplete fix of the same class: the patch added `length < 0` but left `pos + length` able to wrap, so INT_MAX still slipped through [E4](https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md). Fixing one language runtime left sibling implementations unpatched [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-86wm-r4c5-2rc9.md).

## Impact and severity
Ranged from process crash on untrusted input [E3](https://bugbountylibrary.com/r/ghsa%3AGHSA-86wm-r4c5-2rc9.md) and unchecked exceptions instead of decode errors [E4](https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md) to heap overflow and memory disclosure [E2](https://bugbountylibrary.com/r/blog%3Awillsroot-io-2022-01-cve-2022-0185-html.md) to unauthenticated remote command execution [E1](https://bugbountylibrary.com/r/blog%3Arapid7-com-blog-post-ra-gitlab-ci-cd-regex-integer-overflow-technical-analysis-cve-2026-97229.md). Severity rose where the path was reachable pre-auth and where the overflow landed in a predictable slab or buffer.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Arapid7-com-blog-post-ra-gitlab-ci-cd-regex-integer-overflow-technical-analysis-cve-2026-97229.md
- E2: https://bugbountylibrary.com/r/blog%3Awillsroot-io-2022-01-cve-2022-0185-html.md
- E3: https://bugbountylibrary.com/r/ghsa%3AGHSA-86wm-r4c5-2rc9.md
- E4: https://bugbountylibrary.com/r/ghsa%3AGHSA-9rm7-3qhh-h2mc.md
