Optimizer reuses a type assumption across a map change
A TurboFan/Maglev speculation keyed on an object’s map, field representation, or Smi-ness is not invalidated when a migration, deopt, or in-place reconfigure changes it — so post-change memory is read with the pre-change type.
Mechanism
V8’s optimizing tiers cache type/field/representation facts to elide checks and reuse loads. But a CheckMaps with kTryMigrateInstance, a deopt materialization, an in-place map reconfigure (Smi→Double via a mutable HeapNumber), or phi untagging can change the object’s actual shape mid-stream.
When the optimizer fails to kill the dependent assumption at that edge, it reuses a stale PropertyArray/in-object load or an elided CheckSmi/CheckHeapObject, reading the post-change bytes with the pre-change type. That is a type confusion — a tagged pointer read as a Smi, a double read as an object pointer — and a direct path to arbitrary read/write in the renderer.
Fix shape
Invalidate the dependent state on the exact map-changing edge:
KillFields/KillConstFieldon aCheckMapsthat carries a migrate flag (LoadElimination).- Re-add the widened type (
UnionType(kHeapNumber)) after strippingkSmi. - Only elide
CheckSmiwhen the caller sayselidable. - Force a fresh
HeapNumberper deopt materialization instead of deduplicating a mutable box.
CVEs in this pattern
1 component · V8| CVE | What | Component | Vendor | Severity | Month | |
|---|---|---|---|---|---|---|
| CVE-2026-87587 | UAF in V8 | V8 | chrome | High | 2026-09 | 🔧 |
| CVE-2026-85045 | Race in V8 | V8 | chrome | High | 2026-09 | 🔧 |
| CVE-2026-79236 | TypeConfusion in V8 | V8 | chrome | High | 2026-08 | 🔧 |
| CVE-2026-76038 | TypeConfusion in V8 | V8 | chrome | High | 2026-08 | 🔧 |
| CVE-2026-15903 | OOB in V8 | V8 | chrome | High | 2026-07 | 🔧 |
| CVE-2026-17725 | TypeConfusion in V8 | V8 | chrome | High | 2026-07 | 🔧 |
| CVE-2026-11645 | OOB in V8 | V8 | chrome | High | 2026-06 | ⚠️ 🔧 |
| CVE-2026-14431 | TypeConfusion in V8 | V8 | chrome | High | 2026-06 | 🔧 |
| CVE-2026-8570 | TypeConfusion in V8 | V8 | chrome | Medium | 2026-05 | 🔧 |
| CVE-2026-8540 | TypeConfusion in V8 | V8 | chrome | High | 2026-05 | 🔧 |
| CVE-2026-5865 | TypeConfusion in V8 | V8 | chrome | High | 2026-04 | 🔧 |
| CVE-2026-5871 | TypeConfusion in V8 | V8 | chrome | High | 2026-04 | 🔧 |
| CVE-2026-7337 | TypeConfusion in V8 | V8 | chrome | High | 2026-04 | 🔧 |
| CVE-2025-13223 | TypeConfusion in V8 | V8 | chrome | High | 2025-11 | ⚠️ 🔧 |
| CVE-2025-5419 | OOB in V8 | V8 | chrome | High | 2025-06 | ⚠️ 🔧 |
| CVE-2025-5280 | OOB in V8 | V8 | chrome | High | 2025-05 | 🔧 |
| CVE-2025-2135 | TypeConfusion in V8 | V8 | chrome | High | 2025-03 | 🔧 |
| CVE-2025-0291 | TypeConfusion in V8 | V8 | chrome | High | 2025-01 | 🔧 |
Hunt for siblings
Mostly a code-review pattern: compare the lifetime of each cached optimizer assumption against the ops that can change an object’s map. The greps locate the edges to audit.
# Map-changing edges and the speculation sites that must invalidate on them:
rg -n 'kTryMigrateInstance|MigrateToMap|CheckMapsFlag|CreateUnduplicatableId|SetUseRequiresHeapObject|GetDuplicatedId' \
src/compiler src/maglev
# Then: for each, confirm a KillFields/KillConstField (or fresh-materialization) on that edge.
Mitigations that would catch this class
- V8 sandbox +
SBXCHECK— contains the corruption to the sandbox even when the confusion fires - Differential fuzzing of each optimizer tier against the interpreter (divergent field values are this class’s signature)
- Assert map stability across a speculative region (the invariant, checked)