# JIT type check elided after mutation

Optimized code keeping stale type or field-layout assumptions after a mutation path skips deoptimization

_Area: Memory corruption and native code. Seen in 2 disclosed reports; latest 2022-11-08. Updated 2026-11-01._

## How it works
An optimizing JIT compiles code on the assumption that a variable or field has a certain type or layout, and relies on deoptimization to bail out when that assumption stops holding. The bug is a mutation path that changes the type or layout but fails to trigger that bail-out. The optimized code then keeps using the old offsets or the old type, and a value of one type is treated as another (type confusion). The broken invariant: every path that can invalidate a compiled assumption must deoptimize dependent code, or the assumption must be re-checked before use.

## Where it shows up
- Optimizer paths that skip re-validation when a variable is reassigned, especially inside nested loops [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md).
- Store paths that handle a degenerate type state (e.g. a cleared `None` FieldType) for one access mode but not another, such as `kStore` vs `kStoreInLiteral` [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md).
- Weak-map-collected field types that should force generalization and deopt but don't [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md).
- Deopt literals holding a mutable box (e.g. a mutable HeapNumber) so reconstructed objects share one mutable value [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).
- Downstream code that treats a sandbox "detached" or "frozen" state as immutable when the sandbox does not enforce that [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).

## How to review
For each compiled assumption, enumerate every path that can change the underlying type or layout, and confirm each one deoptimizes or re-checks. The property to hold: no mutation can leave optimized code running against a stale map, field offset, or type. Check that degenerate type states are handled symmetrically across all access modes [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md), that reassignment inside loops re-validates the variable's type [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md), and that deopt literals are immutable or copied per reconstruction [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md). For sandboxed consumers, verify they do not assume a detached or frozen state is immutable [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).

## How finders spotted it
- Reasoned about obligations the V8 sandbox imposes on downstream consumers and looked for code assuming transferred buffers were immutable [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).
- Noticed a retry path inferred source geometry from a failed read, an assumption broken by a process-freeze flag [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).
- Patch analysis pointed to a flawed check in `GlobOpt::OptArraySrc` / `ShouldExpectConventionalArrayIndexValue`; variant analysis from a prior fuzzed bug [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md).
- Targeted audit of `None` FieldType handling, noting fuzzers would struggle without support for computed-key literal stores [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md).

## Variants seen
- JIT assumes a variable keeps its typed-array type after reassignment to an Object, using array offsets on an Object [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md).
- FieldType cleared by weak-map collection skips generalization on literal stores, leaving stale map assumptions [E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md).
- Mutable HeapNumber stored as a deopt literal, breaking the immutable-HeapNumber invariant [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md).

## Impact and severity
Type confusion yields relative then arbitrary read/write, then code execution via fake vtable or shellcode [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md)[E3](https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md). In E1 three independent invariant violations chained across the V8 cage, renderer sandbox, and Crashpad handler to reach unsandboxed execution [E1](https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md). Impact rises with chaining and with how far the confused value reaches; CFG was bypassed because VirtualProtect marked pages as valid call targets [E2](https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Axbow-com-labs-research-zero-to-calc-in-six-days-inside-xbow-chrome-full-chain.md
- E2: https://bugbountylibrary.com/r/p0%3ACVE-2022-41128.md
- E3: https://bugbountylibrary.com/r/p0%3ACVE-2022-3723.md
