Garbage Collection in V8
Richard Abou Chaaya (Security Researcher · Tencent), John Stephenson (Security Researcher · Tencent)
OffensiveCon 2025 · Day 1 · Main · Briefings
Overview
Researchers Richard Abou Chaaya and John Stephenson from Tencent demonstrate how a previously reported V8 bug — dismissed as non-exploitable — becomes a critical use-after-free under V8's new Minor Mark Sweep (MinorMS) garbage collector. Paired with a GC-triggered V8 heap sandbox escape, the two bugs form a complete remote code execution exploit chain against Chrome. The talk is grounded in a rigorous explanation of garbage collection theory, showing that the switch from the Scavenger GC to MinorMS changed fundamental invariants that previous exploitability assessments relied upon. ---

Key moments
- 0:45 MinorMS non-moving GC flips previously dismissed bug exploitable
- 1:53 Generational GC hypothesis explained as foundation for understanding the exploit
- 3:34 Conservative stack scanning project requires MinorMS non-moving GC design
- 7:31 gcmole misses raw Tagged<> pointer misuse in deep call chains
- 12:37 Scavenger moves objects — masked bug as non-exploitable
- 18:22 Array shift left-trim UAF: non-exploitable under Scavenger, exploitable under MinorMS
- 22:09 MinorMS sweeper overwrites freed memory predictably enabling reliable heap reclaim
- 25:36 GC metadata writes raw addresses enabling heap sandbox escape
Garbage Collection in V8: Turning a Non-Exploitable Bug Into a Chrome RCE
Speakers: Richard Abou Chaaya & John Stephenson (Tencent)
Conference: OffensiveCon 2025 — May 16–17, 2025, Berlin
YouTube: https://www.youtube.com/watch?v=sM2d0ciaeiI
Reading time: ~10 minutes
TL;DR
Researchers Richard Abou Chaaya and John Stephenson from Tencent demonstrate how a previously reported V8 bug — dismissed as non-exploitable — becomes a critical use-after-free under V8's new Minor Mark Sweep (MinorMS) garbage collector. Paired with a GC-triggered V8 heap sandbox escape, the two bugs form a complete remote code execution exploit chain against Chrome. The talk is grounded in a rigorous explanation of garbage collection theory, showing that the switch from the Scavenger GC to MinorMS changed fundamental invariants that previous exploitability assessments relied upon.
Introduction
Browser exploit research frequently focuses on JavaScript engine JIT compilers, but the garbage collector — the infrastructure responsible for tracking which JS objects are alive and reclaiming the rest — is an equally consequential and considerably less studied attack surface. At OffensiveCon 2025, Richard Abou Chaaya and John Stephenson from Tencent presented the first public exploit chain whose critical link is a change in V8's garbage collection algorithm.
The key insight is deceptively simple: when Google engineers introduced MinorMS — a new mark-sweep-based collector for the V8 young generation — they changed the object lifecycle in ways that transformed a formerly inert dangling-pointer bug into an exploitable use-after-free. This talk is significant not only for the bugs disclosed but for the methodology it introduces: monitoring GC algorithm changes as a trigger for re-evaluating the exploitability of previously dismissed issues.
Garbage Collection Fundamentals: The Pointer-Finding Problem
▶ Watch: GC Theory and Pointer Finding (0:00)
The talk opens with foundational GC theory oriented toward security researchers rather than language implementors. The central challenge in any GC is determining which objects are still reachable — the reachability problem — by starting from a root set (stack variables, registers, global references) and tracing the object graph.
V8 divides the JavaScript heap into two generations based on the generational hypothesis: most objects die young, so short-lived allocations sit in the young generation (collected frequently) and survivors are promoted to the old generation (collected infrequently). This division is critical because the two spaces can run different collection algorithms.
▶ Watch: Precise Root Tracking vs. Conservative Stack Scanning (2:00)
For finding pointers in JS heap objects, V8 uses type-specific visitor functions — each object type declares exactly which of its fields are pointers. The harder problem is the C++ call stack, where the layout of frames is not formally specified. V8 has historically solved this with precise root tracking via Handle<T> wrapper types: any C++ code that holds a reference to a JS heap object must wrap it in a Handle, which registers the reference with the GC via constructor/destructor callbacks. The set of live handles at any moment is the GC's precise root set.
The cost of precise root tracking is twofold: performance overhead from per-handle allocation and callback registration, and developer burden — programmers must correctly reason about when GC can occur and either wrap references in Handle or use raw pointers only in GC-free zones. V8's gcmole static analysis tool tries to catch misuse, but as the presenters demonstrate with a live example from the V8 codebase, it is imperfect.
The Scavenger vs. Minor Mark Sweep
▶ Watch: Scavenger GC Design (12:00)
V8's original young-generation collector, the Scavenger, uses a classic semi-space design: the heap is divided into "from" and "to" spaces. Live objects are copied from the from-space into the to-space during collection; unreachable objects are left behind. The from- and to-space labels then swap, making the to-space the new allocation arena. This algorithm achieves excellent compaction but has a critical constraint: it moves objects, and moving objects requires updating every pointer to a moved object. This is only possible if the GC knows precisely which values on the stack are pointers — i.e., it requires precise root tracking, not conservative stack scanning.
▶ Watch: Minor Mark Sweep Introduction (14:00)
The V8 team's ongoing project to adopt conservative stack scanning (treating any stack value as a potential pointer, eliminating handle overhead) is fundamentally incompatible with the Scavenger because the GC cannot safely update values that might not actually be pointers. To resolve this, the team implemented Minor Mark Sweep (MinorMS): a mark-and-sweep algorithm for the young generation that does not move objects. MinorMS marks live objects using a per-page bitmap, then sweeps in place, coalescing dead regions into a free list. Object promotion from young to old space happens by setting a flag in the object's metadata rather than by physically copying.
This design change — objects are no longer moved during young-generation collection — is precisely the change that makes a previously dismissed bug exploitable.
The Previously Non-Exploitable Bug Becomes Exploitable
▶ Watch: Bug Reanalysis Under MinorMS (8:00)
The first bug in the exploit chain was a handle-misuse pattern in V8's C++ code: a reference to a JS heap object (specifically, deoptimization data) was held as a raw Tagged<> pointer rather than a Handle<>. A function called shortly afterward could trigger garbage collection through a heap allocation. If GC ran at that point, the Scavenger would potentially move the deoptimization object to the to-space — and because the reference was not a Handle, the GC would not update it. The result was a dangling pointer to freed memory in the from-space.
Under the Scavenger, this bug was assessed as non-exploitable for a specific reason: the from-space, after collection, is entirely overwritten with newly allocated young-generation objects on the next GC cycle. The window for exploitation — between the object being moved and the from-space being reused — was considered too narrow and the from-space contents too uncontrolled to reliably land a useful allocation at the right address.
Under MinorMS, this analysis no longer holds. Because MinorMS does not move objects and instead marks them in-place, the "moved object" scenario cannot occur in the same way. However, MinorMS introduces a different lifecycle: dead objects' memory is made available via the free list, and the free list can be serviced by subsequent allocations in a far more predictable order. The presenters show that with MinorMS, an attacker can trigger GC at the right moment, ensure the target object is freed and its memory reclaimed by a controlled allocation, and access the dangling pointer in the window before the reclaimed memory is overwritten — yielding a classical use-after-free with attacker-controlled content at the freed address.
GC-Triggered V8 Heap Sandbox Escape
▶ Watch: Heap Sandbox Escape (0:00)
The second bug in the chain targets V8's heap sandbox — a containment mechanism designed to limit the blast radius of in-sandbox memory corruption by isolating the JS heap from the rest of the browser process address space. Pointers between sandboxed JS heap objects use sandbox-relative offsets rather than raw addresses, so corrupting an in-sandbox pointer should not give an attacker a useful address outside the sandbox.
The researchers found a GC-related path through which sandbox invariants can be violated. During garbage collection, certain metadata updates — specifically those performed when a GC root is updated or when an object is promoted from young to old generation — are performed by code that operates on raw process addresses rather than sandbox-relative references. By triggering collection at a controlled point and influencing which objects are promoted or which roots are updated, an attacker who has achieved in-sandbox arbitrary write (via the first bug) can cause a GC metadata update to write an attacker-controlled absolute address into a location that the V8 heap sandbox normally treats as protected. This breaks sandbox containment and yields out-of-sandbox code execution — the final step to full Chrome renderer RCE.
Notable Quotes
"We have two main bugs that will constitute a full remote code execution exploit against Chrome. But to get there, we need to learn about some garbage collection theory."
— Richard Abou Chaaya, ▶ 0:00
"Using a direct pointer when GC can occur can lead to a use-after-free or a dangling pointer. And conversely, using a handle when GC cannot occur leads to bad performance. The gcmole tool tries to statically look for handle misuse, but this tool is not perfect."
— John Stephenson, ▶ 6:00
"Conservative stack scanning can only be used if the GC algorithm offers a mechanism for pinning objects in place. Moving objects is incompatible with conservative stack scanning, because if we move an object, we have to also update all references to it — but if some referring value was not a pointer but just a misclassified integer, we'd end up corrupting its value."
— John Stephenson, ▶ 10:00
Key Takeaways
- GC algorithm changes can flip exploitability. A bug dismissed as non-exploitable under one GC design (the Scavenger) became exploitable when MinorMS changed object lifecycle semantics. Security teams should re-audit old dismissed issues whenever significant GC algorithm changes land.
- Precise root tracking via Handle<T> is error-prone by design. V8's
gcmoletool finds some misuse but misses patterns involving multi-level call stacks; any V8 code that uses rawTagged<>pointers in functions that can trigger allocation is a candidate for dangling-reference bugs. - Conservative stack scanning creates new GC invariants. The ongoing V8 project to replace handles with conservative stack scanning introduces MinorMS, which trades compaction (object movement) for developer ergonomics. This trade creates a new class of GC-specific exploitability conditions that need fresh threat modeling.
- The V8 heap sandbox is not a complete containment boundary. GC metadata operations that use raw process addresses provide a structural path from in-sandbox corruption to out-of-sandbox code execution, contingent on controlling GC timing.
- Exploit chains increasingly live at infrastructure boundaries. This research demonstrates that the highest-leverage modern browser bugs are not in JS semantics or JIT correctness but at the intersection of memory management infrastructure (GC) and security boundaries (the heap sandbox) — areas that change with performance engineering goals rather than feature development.
Reviews
Dr. Zero (Offensive Security Researcher) — MUST SEE
Chaaya and Stephenson took a V8 bug previously dismissed as non-exploitable, showed that the switch from Scavenger GC to Minor Mark Sweep changed the object lifecycle in exactly the way needed to make the UAF reliable, then chained it with a GC-triggered V8 heap sandbox escape to achieve full Chrome RCE. The methodology — monitor GC algorithm changes to re-audit dismissed bugs — is a new research primitive. Accept immediately.
Heather Calloway (CISO) — PASS
A GC algorithm change in Chrome's V8 (MinorMS replacing Scavenger) retroactively converted a previously-dismissed bug into a UAF, enabling a complete Chrome RCE chain. Highly technical browser internals research.