# Unvalidated type or shape assumption

Casts, pops, frees, or field reads that trust an object's type or stack shape without a runtime check

_Area: Memory corruption and native code. Seen in 10 disclosed reports; 3 confirmed bounties, median $91,337, range $1,000-$117,000; latest 2026-07-17. Updated 2026-10-23._

## How it works
Code obtains an object, value, or stack slot and assumes its type or shape from context rather than from a runtime tag or shape check. When the assumption is false, fields are read or written at the wrong offsets, a pointer of the wrong type is freed, or a value is popped that was never pushed. The root cause is a static belief about type, representation, or shape standing in for a check that must hold at runtime. A close relative is identity confusion: code assumes the current task or context is the one that owns an object [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md).

## Where it shows up
- Lookup-by-ID handlers that fetch an object and cast it without verifying its type tag [E3](https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md)
- Push/pop or alloc/free pairs whose conditions differ (push conditional on attributes, pop unconditional) [E6](https://bugbountylibrary.com/r/h1%3A188661.md)
- Compiler helpers that prove a value by range (e.g. Smi::IsValid) instead of by type [E2](https://bugbountylibrary.com/r/blog%3Ablog-calif-io-p-journey-to-root-episode-i-the-maglev.md)
- Async paths that assume the current task is the submitter [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md)
- Recursion on AST children without validating the node is well-formed [E5](https://bugbountylibrary.com/r/h1%3A191689.md)
- zval pointers reused across loop iterations and dereferenced as a container without a type check [E4](https://bugbountylibrary.com/r/h1%3A172411.md)

## How to review
For every cast, pop, free, or field access, ask: what runtime check guarantees this object is the expected type? The invariant is that type identity is established by an explicit tag or shape check at the point of use, not inferred from origin. Correct checks look like: a tag compare before the cast [E3](https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md); a type test (not a range test) before eliding a barrier [E2](https://bugbountylibrary.com/r/blog%3Ablog-calif-io-p-journey-to-root-episode-i-the-maglev.md); a `Z_TYPE_P(ptr) == IS_ARRAY` guard before `Z_ARRVAL_P` [E4](https://bugbountylibrary.com/r/h1%3A172411.md); a node-kind check before recursing [E5](https://bugbountylibrary.com/r/h1%3A191689.md). Compare paired operations (push/pop, alloc/free, init/teardown) and confirm their conditions match exactly [E6](https://bugbountylibrary.com/r/h1%3A188661.md). In async code, confirm the acting task is the object's owner, not merely the current one [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md).

## Variants seen
- Task-identity confusion in async request handling [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md)
- Representation confusion: range test standing in for a type test [E2](https://bugbountylibrary.com/r/blog%3Ablog-calif-io-p-journey-to-root-episode-i-the-maglev.md)
- Mach service object fetched by ID and cast without validation [E3](https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md)
- zval reinterpreted as HashTable without a type check [E4](https://bugbountylibrary.com/r/h1%3A172411.md)
- Node-shape validation skipped on recursion, letting raw bytes reach metadata fields [E5](https://bugbountylibrary.com/r/h1%3A191689.md)
- Stack shape/state desync from mismatched push/pop conditions [E6](https://bugbountylibrary.com/r/h1%3A188661.md)

## Impact and severity
Led to invalid free and, after a full chain, container escape [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md); renderer RCE [E2](https://bugbountylibrary.com/r/blog%3Ablog-calif-io-p-journey-to-root-episode-i-the-maglev.md); code execution [E3](https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md); heap overflow and likely RCE [E4](https://bugbountylibrary.com/r/h1%3A172411.md); assert crash [E5](https://bugbountylibrary.com/r/h1%3A191689.md); invalid read [E6](https://bugbountylibrary.com/r/h1%3A188661.md). Severity rises when the confused object is attacker-influenced and the path reaches a free or control-flow target; uninitialized memory and heap layout control made exploitation reliable [E1](https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md)[E3](https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Ablog-kylebot-net-2022-10-16-cve-2022-1786.md
- E2: https://bugbountylibrary.com/r/blog%3Ablog-calif-io-p-journey-to-root-episode-i-the-maglev.md
- E3: https://bugbountylibrary.com/r/blog%3Aprojectzero-google-2026-01-sound-barrier-2-html.md
- E4: https://bugbountylibrary.com/r/h1%3A172411.md
- E5: https://bugbountylibrary.com/r/h1%3A191689.md
- E6: https://bugbountylibrary.com/r/h1%3A188661.md
