# Property interceptor reentrancy corruption

Engine code that runs user JS mid-property-assignment, then trusts a stale lookup result

_Area: Memory corruption and native code. Seen in 2 disclosed reports; latest 2022-03-25. Updated 2026-10-23._

## How it works
A property assignment runs an interceptor (a getter/setter, proxy trap, or engine-internal hook) that calls back into user JavaScript. That user code can redefine the very property being assigned. The engine, however, keeps using the lookup result it computed before the callback ran — typically "property is ABSENT" — and proceeds to add the property. The result is a duplicate property or a double-add, which corrupts the object's map/descriptor state and can turn into type confusion.

## Where it shows up
- SetPropertyInternal-style paths that query a prototype interceptor, then add a property based on the earlier ABSENT result.
- Interceptors on DOM objects (e.g. HTMLEmbedElement, CSSStyleDeclaration) that can execute script.
- JS-implemented builtins using ordinary array operations (push, indexed assignment) on default-constructed arrays, where a prototype setter can intercept.
- Code that calls UnsafeSetReservedSlot or similar unchecked slot writes on objects reachable from user JS.
- Alternate entry points (Object.defineProperty / DefineOwnPropertyIgnoreAttributes) that skip the interceptor path.

## How to review
The invariant: after any callback into user code, the engine must re-check the property's state before acting on it. Trace every interceptor call site and ask whether the code re-reads the descriptor/map after the callback returns. Confirm the add-property step is guarded by a fresh lookup, not a cached ABSENT. For builtins, check that internal objects are never exposed to prototype setters and that slot writes are bounds-checked.

## Variants seen
- Duplicate property added after interceptor redefines it, corrupting map/descriptor state [E1](https://bugbountylibrary.com/r/p0%3ACVE-2021-30551.md).
- Prototype setter intercepts push on a default array, leaking an internal Module object, then unchecked slot write [E2](https://bugbountylibrary.com/r/blog%3Azerodayinitiative-com-blog-2022-8-17-but-you-told-me-you-were-safe-attacking-the-mozilla-firefox-renderer-part-1.md).
- Interceptor runs JS that adds the property, then code adds it a second time, causing type confusion [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-1096.md).

## Why fixes fail
A patch guarded only one if/else branch of the state re-check; the sibling branch and alternate entry points like Object.defineProperty remained reachable [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-1096.md).

## Impact and severity
Type confusion leading to renderer RCE; one case was exploited as a Chrome 0-day [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-1096.md). Severity is high because the corruption is reachable from ordinary script and feeds JIT type confusion [E1](https://bugbountylibrary.com/r/p0%3ACVE-2021-30551.md).

## Evidence
- E1: https://bugbountylibrary.com/r/p0%3ACVE-2021-30551.md
- E2: https://bugbountylibrary.com/r/blog%3Azerodayinitiative-com-blog-2022-8-17-but-you-told-me-you-were-safe-attacking-the-mozilla-firefox-renderer-part-1.md
- E3: https://bugbountylibrary.com/r/p0%3ACVE-2022-1096.md
