Summary
CVE: CVE-2024-6773 Component: V8 Turboshaft (Load Elimination) Vulnerability Type: Type confusion → memory corruption (stale pointer across GC) Vendor: Google Product: Chrome / V8 JavaScript Engine Affected Versions: Chrome versions prior to M126 Fix Status: Fixed (V8 main + backports to M126 Stable / M127 Beta) Severity: Chrome S1 Credit: Salim Largo (2ourc3)
Description
CVE-2024-6773 is a critical type confusion vulnerability in the V8 Turboshaft compiler pipeline, specifically within the Load Elimination optimization phase.
The bug allowed Turboshaft to incorrectly keep a raw pointer value alive across a garbage collection (GC) boundary. Because raw pointers are not tracked as GC-managed references, the GC could relocate the underlying heap object while the compiler continued using the stale pointer value. This produced an exploitable situation where optimized code could dereference a dangling pointer, leading to memory corruption.
Root cause
The issue originates from how Turboshaft handled redundant LoadStackArgument operations during Load Elimination.
Original code pattern
x = LoadStackArgument(a, 40) // First load
...
Allocate() // Potential GC trigger
...
y = LoadStackArgument(a, 40) // Redundant load
Faulty optimization
Turboshaft lowered the first load into a raw pointer load (WordPtr), then applied a tagged cast, and later reused the same raw value after an allocation (GC point):
x1 = Load<WordPtr>(...) // Raw pointer
x2 = TaggedBitcast(x1) // Tagged pointer
...
Allocate() // GC may relocate objects
...
y2 = TaggedBitcast(x1) // Uses stale x1 after GC
Because Load Elimination removed the “redundant” second load, it unintentionally caused the raw pointer (x1) to survive across GC. Since the GC cannot update WordPtr values like it updates tagged pointers, this created a stale/dangling reference after heap compaction.
Impact
This bug is a strong exploitation primitive:
- Type confusion vector: the engine uses a stale pointer but treats it as a valid tagged reference.
- Memory corruption: stale pointer dereference after GC relocation can corrupt adjacent objects or metadata.
- Primitive potential: can be shaped into arbitrary read/write under controlled heap and timing conditions.
Although the exploit requires GC involvement, it was reproducible through structured JavaScript payloads.
Crash signature observed: SEGV_ACCERR at 0x22e4beadbef6 (stale pointer dereference)
Fix
The vulnerability was resolved by ensuring LoadStackArgument loads remain GC-trackable tagged pointers, rather than raw pointer loads combined with tagged bitcasts.
In practice: instead of retaining a WordPtr across a safepoint, the compiler now preserves a tagged representation so the GC can properly track and update it when objects move.
Timeline
| Date | Action |
|---|---|
| 2024-06-17 | Vulnerability reported |
| 2024-06-19 | Fix merged into V8 main branch |
| 2024-06-25 | Backported to Chrome M126 (Stable) |
| 2024-06-25 | Backported to Chrome M127 (Beta) |
References / credits
- Discoverer: Salim Largo (2ourc3), via fuzzing
- Fix author: Darius Mercadier (V8 Security Team)
- Disclosure: Coordinated via Chrome VRP
- CVE: CVE-2024-6773
Lessons learned
- Optimizations must respect GC safepoints: raw pointer lifetimes must never span relocation points unless explicitly rooted.
- Type tracking must remain correct across lowering: changing representations (tagged → raw) must be audited for GC correctness.
- Fuzzing works on compiler pipelines too: modern JIT/optimizing compilers remain a high-value surface for memory corruption bugs.