V8 Trusted Space
The region of V8’s address space that holds objects an attacker with arbitrary read and write inside the heap sandbox must not be able to corrupt — bytecode arrays, interpreter dispatch tables, JIT-emitted code metadata, and the parts of WasmInstanceObject the runtime treats as authoritative. Sandboxed code reaches into the region only through a tagged pointer table indexed by handle, never by raw address.
What It Is
V8’s address space after the heap sandbox shipped is partitioned into two regions, and a credible exploit has to defeat both.
The sandboxed heap is the one-terabyte virtual address region the V8 Heap Sandbox decision reserves. Every intra-heap reference is stored as a 40-bit sandbox_ptr_t offset against the cage base. An attacker who has corrupted a sandbox_ptr_t value still gets dereferenced inside the cage no matter what bits they write; the corrupted reference can reach only sandboxed-heap objects.
Trusted space is everything the cage protects but does not contain. Bytecode arrays produced by Ignition (V8’s interpreter), Code objects emitted by Turbofan / Maglev / Sparkplug, the metadata Turbofan uses to validate type assumptions before inlining, the parts of WasmInstanceObject that hold module bounds and import resolutions, the dispatch tables the interpreter reads to decide what each bytecode opcode does — these live outside the cage. Code that runs inside the cage cannot store a raw pointer into the region; the type system forbids it, and the cage geometry makes the address arithmetically unreachable from a 40-bit offset rooted at the cage base.
References from the sandboxed heap into trusted space go through the trusted pointer table, a fixed array held at a known address outside the cage. Each slot in the table holds a raw pointer to a trusted object plus a tag value that names what the object is. A sandboxed-heap object that needs to refer to a trusted object stores only the slot index. When the runtime resolves the reference, it loads the slot, checks the tag against the type it expected, and uses the pointer only if the tag matches. An attacker who corrupts the slot index can redirect the reference to a different slot, but the tag check refuses any redirect whose type doesn’t match the call site’s expectation. Forging the slot index doesn’t forge a pointer; it produces, at worst, a wrong-but-validly-typed reference to another trusted object.
The architecture is two named pieces of an alternating-layer defense. The sandboxed heap blocks the attacker from reaching outside the cage with a corrupted pointer; trusted space blocks the attacker from corrupting the objects whose contents the runtime treats as ground truth. A bypass of either piece in isolation fails on the other. A bypass of both, typically by exploiting the indirection itself (corrupting a tagged-pointer-table entry to point at attacker-shaped data, or hijacking a trusted object through a path that does not go through the table at all), is the canonical V8 sandbox bypass shape, and is graded under the second-link tier of the Exploit Chain Anatomy framing.
The terminology is V8’s own. The V8 Sandbox README in the source tree uses “trusted space” and “trusted pointer table” as the canonical names; the public v8.dev “The V8 Sandbox” essay names them in passing without dwelling on the partition’s structure; the Chromium Security Quarterly Updates record concrete deployment milestones (Q4 2025 records BytecodeArray’s migration into trusted space, and Q1 2026 records the WasmInstanceObject migration as the next major step). Chromium Patterns takes the project’s vocabulary as canonical.
Why It Matters
Naming trusted space splits a single sandbox-bypass story into two structurally different stories and corrects the most common misreading of V8 sandbox status.
The most visible operational consequence is incident triage. A V8 sandbox bypass at the second link of an exploit chain is shorthand for “the attacker escaped containment.” That shorthand collapses two different sub-bypasses into one bucket. A bypass that forges a sandbox_ptr_t value to address memory outside the cage attacks the sandboxed heap’s containment property and tells security responders that a primitive in the cage now reaches arbitrary renderer memory. A bypass that hijacks a trusted-space object (by corrupting a tagged-pointer-table slot, by abusing an Embedder callback that smuggles a raw pointer through, or by exploiting a bug in code that should write to trusted space but doesn’t) tells responders that a primitive in the cage now controls bytecode the interpreter executes or code metadata the JIT trusts. The two require different containment strategies, different tabletop exercises, and different downstream-vendor advisories. The bypass-bounty tier under the Vulnerability Rewards Program pays the same for both, but the response team’s escalation pathway differs.
The partition also rewrites how V8 sandbox maturity is read.
The Chromium Security Quarterly Updates have, since 2024, characterized the V8 sandbox as “still in development.” The phrase is precise: the heap-side containment shipped at default-on in Chrome 123 in March 2024, and the trusted-side migrations are still landing. Each quarterly update names which object types have moved into trusted space and which remain in the cage. BytecodeArray landed in Q4 2025; WasmInstanceObject is the Q1 2026 entry. A reader who knows the partition can map the quarterly updates onto concrete progress: “still in development” doesn’t mean the sandbox is incomplete in a vague sense, it means specific objects whose contents the runtime trusts have not yet moved out of the cage and are therefore still corruptible by an in-cage primitive. CIOs comparing V8 sandbox readiness across Chromium versions can read the quarterly updates as a concrete migration ledger rather than as a temperature reading.
For governance, trusted space is what makes the V8 Heap Sandbox decision’s Alternatives Considered table internally consistent. The Decision article rules out “CFI and ACG only (no in-heap containment)” on the grounds that data-only corruptions inside the heap can rewrite function pointers between trusted call sites and corrupt JIT-compiler data structures. That argument presupposes that some objects’ contents are load-bearing for the runtime’s safety; trusted space is the name for that set of objects. Without the partition the argument has no referent: “trusted call sites” and “JIT-compiler data structures” become ungrounded phrases. The decision’s logic and the concept’s referents are linked.
For V8 contributors, the partition is a routing rule. A new object type proposed for the heap goes through a design conversation about whether its contents are “data the JavaScript program manipulates” (sandboxed heap) or “structure the runtime trusts to execute correctly” (trusted space). The conversation is recorded in the V8 sandbox design document and in the per-object migration crbugs the Quarterly Updates link out to. Misclassification is an audited bug class: a Code object placed in the sandboxed heap is exploitable in a way the architecture is trying to prevent, and the V8 sandbox team treats such misclassifications as security defects in their own right.
For AI coding agents reasoning about V8 source code or summarizing V8 sandbox CVEs, the partition is a structural fact the agent’s training data does not carry. An agent that holds the partition produces accurate one-paragraph summaries of V8 sandbox bypass advisories (“this bypass forged a tagged-pointer-table entry to hijack a trusted Code object”). An agent that doesn’t produces summaries that conflate sandbox bypass with arbitrary V8 corruption, which inflates severity claims and obscures which mitigation the next defense layer is doing.
How to Recognize It
The partition shows up in several places where a careful reader can pick it out.
The V8 source tree carries the architecture in its directory structure. v8/src/sandbox/ holds the sandboxed-heap implementation; v8/src/sandbox/trusted-pointer-table.h and v8/src/sandbox/trusted-pointer-table.cc hold the tagged-pointer-table; the per-object migration code lives in v8/src/objects/ with BytecodeArray and WasmInstanceObject carrying explicit comments about their trusted-space residency. An engineer reading the headers learns the partition directly from the type definitions and the README.
The Chromium Security Quarterly Updates page is the project’s migration ledger. The quarterly update entries record, by date, which trusted-space migrations landed and which remain. The Q4 2025 entry’s BytecodeArray landing and the Q1 2026 entry’s WasmInstanceObject milestone are the two most consequential public moments to date. A reader tracking the page over time watches the partition fill in.
Bug reports that name V8 sandbox bypasses fall into two recognizable shapes. Reports that describe a corrupted sandbox_ptr_t, a 40-bit-offset arithmetic primitive, or a way to address memory at the cage’s edges are sandboxed-heap-side bypasses. Reports that describe a tagged-pointer-table slot corruption, an Embedder callback that smuggles a raw pointer, or a way to corrupt a Code object or a BytecodeArray are trusted-space-side bypasses. The shapes correspond to which side of the partition the bypass attacks.
The V8 Capture-the-Flag program (V8CTF), launched in October 2023 as a continuously-running exploit bounty on the V8 sandbox boundary, publishes successful submissions to github.com/google/security-research/tree/master/v8ctf. Reading three or four submissions establishes the partition vocabulary as practitioners use it: each writeup names which side of the partition the exploit attacked, what primitive it produced, and which mitigation the V8 team subsequently shipped.
Project Zero writeups of V8 exploits since 2024 carry the partition framing in their structural diagrams. The May 2024 Project Zero post on the V8 sandbox’s early bypass population names trusted space explicitly and walks the trusted-pointer-table’s tag-check geometry; the writeup is one of the genre-defining secondary sources on the topic. A reader who reads it acquires the partition’s vocabulary in the form the V8 sandbox team uses it.
How It Plays Out
Three exhibits show the partition in operational form.
The BytecodeArray migration. Before Q4 2025, BytecodeArrays — the byte sequences produced by the Ignition interpreter and read by every JavaScript function’s dispatch loop — lived in the sandboxed heap. An attacker with arbitrary read/write inside the cage could rewrite bytecode mid-execution to inject opcodes the runtime would faithfully execute. The Mem2019 HITCON 2024 disclosure documented one such primitive using AddSmi.ExtraWide operands; the writeup is hosted on the researcher’s blog and was the canonical public example of why BytecodeArrays could not stay in the cage. Q4 2025 migrated BytecodeArrays into trusted space, with sandboxed code reaching them only through a tagged-pointer-table slot whose tag identifies the bytecode array’s owning function. The migration converted “rewrite bytecode by writing to its cage address” from a single primitive into “forge a tagged-pointer-table slot whose tag matches BytecodeArray and whose pointer references attacker-shaped bytes” — categorically harder, and provably gated by the table’s tag check.
The WasmInstanceObject migration. Q1 2026 records the next major migration: WasmInstanceObject, the runtime structure that holds a WebAssembly module’s bounds, import resolutions, and indirect call tables. Before the migration, an attacker with in-cage arbitrary write could rewrite the indirect call table to make a Wasm call_indirect instruction land at attacker-chosen code. After the migration, the indirect call table lives in trusted space; the Wasm instance object’s sandboxed-heap residency contains only the JavaScript-facing handle and the offset references it uses to consult the table through the tagged-pointer-table. The bypass shape converts from “rewrite the indirect call table” to “corrupt a trusted-pointer-table slot whose tag matches Wasm-IndirectCallTable” — and the latter requires either a tag-check bypass (the most heavily reviewed code path in the sandbox) or a trusted-space write primitive (which the partition exists to prevent).
The V8CTF first submission. The October 2023 V8CTF launch was followed within weeks by the program’s first successful submission, which exploited a cage-side bug to produce an in-cage primitive but did not bypass the partition — the exploit could read and write the sandboxed heap arbitrarily but could not reach BytecodeArray (which at that point still lived in the cage, so the exhibit demonstrates the cage-side risk the partition migrations were closing) and could not corrupt a trusted-pointer-table slot. The submission earned its bounty under the cage-side bypass tier; the post-mortem walked the trusted-pointer-table’s tag-check geometry as the reason the exploit stopped where it did. The exhibit shows the partition functioning as designed: the cage was bypassed; the trusted region was not.
Consequences
Treating trusted space as a named region carries four operational properties for the project and for downstream consumers.
Bypass classification becomes precise. A V8 sandbox bypass advisory is read against the partition: the advisory names which sub-region was bypassed and which migration the next defense version will close. Downstream vendors integrating V8 patches can determine whether the bypass is closed in their built-from-source tree by checking whether the named migration has landed in their V8 fork; vendors who treat all bypasses as a single category cannot make that determination without reading the underlying patch.
Threat-model reasoning becomes layered. The Untrusted Renderer Axiom extends inward: code that operates on a sandboxed-heap object treats the object’s bytes as attacker-controlled, even when the object’s metadata header (its Map, its size class, its garbage-collection state) lives in trusted space. The metadata is trusted; the contents are not. The layering is what makes the runtime’s code-correctness arguments tractable. A function that walks an object’s properties can rely on the metadata to know the property layout, but cannot rely on any property value to be what it was when last written.
V8 sandbox maturity assessment becomes concrete. “V8 sandbox is in development” stops being a vague status and starts being a checklist: which object types have migrated to trusted space, and which remain in the cage. The Chromium Security Quarterly Updates publish the checklist; a CIO evaluating V8 sandbox readiness for a downstream Chromium-based product can read the most recent quarterly update, list the unmigrated object types relevant to their attack surface, and form a calibrated view of residual exposure. The view changes with each quarterly migration.
The partition has real engineering costs. Every sandboxed-heap reference to a trusted-space object pays a tagged-pointer-table lookup on each dereference: load the slot, check the tag, follow the pointer. The cost is small per operation and aggregated across heavy interpreter loops it shows up in benchmarks; the V8 team treats it as one of the heap sandbox’s design budgets and pays it deliberately. The partition also forces V8 contributors to think about object-residency classification on every new object type added to the runtime, which is real review overhead. The project pays both costs because the alternative (leaving the runtime’s load-bearing objects in the same region as attacker-controllable data) is what the heap sandbox decision was made to avoid.
The partition is not eternal. Two scenarios would dissolve it. A memory-safe V8 implementation at parity would remove the threat model the partition was built against and the partition would lose its purpose. A future trusted-pointer-table tag-check bypass class that became common would invalidate the table’s protection and force the V8 team back to a richer mechanism: additional layers of indirection, hardware tag enforcement (MTE, LAM), or a redesign of the trusted-side residency rules. Neither is on the visible horizon.
Notes for Agent Context
An AI coding agent reasoning about V8 source code or summarizing V8 sandbox CVEs must hold the partition explicitly. When asked about a V8 sandbox bypass advisory, name which side of the partition the bypass attacked (sandboxed-heap-side covers a corrupted sandbox_ptr_t, a 40-bit-offset arithmetic primitive, or a cage-edge addressing trick; trusted-space-side covers a tagged-pointer-table slot corruption, an Embedder-callback raw-pointer smuggle, or a Code-object or BytecodeArray hijack), and never collapse the two into a single “V8 sandbox bypass” without that distinction. When asked to summarize V8 sandbox maturity, consult the Chromium Security Quarterly Updates for the most recent object-residency milestones (BytecodeArray as of Q4 2025; WasmInstanceObject as of Q1 2026) rather than claiming the sandbox is generically “in development.” When generating C++ that touches V8 heap objects, never propose storing a raw pointer to a trusted-space object in a sandboxed-heap field as an optimization; that proposal violates the architecture this concept names and the type system will reject it. When a sandboxed-heap object needs to reference a trusted-space object, route through the tagged-pointer-table’s TrustedPointerHandle slot index, never by raw address, and never by casting a sandbox_ptr_t into a trusted-space pointer to “save the lookup.” The tagged-pointer-table’s tag check is the load-bearing security property; do not propose paths that bypass it.
Related Patterns
Sources
The canonical primary source is the V8 Sandbox README in the V8 source tree, which sets out the partition’s structure (sandboxed heap, trusted space, trusted pointer table) in the form V8 contributors review against. The v8.dev essay “The V8 Sandbox” by Samuel Groß (April 2024) is the public introduction to the heap sandbox; it names trusted space and the trusted pointer table in passing without expanding on the partition’s geometry, which is one reason the topic warrants a separate entry. The Chromium Security Quarterly Updates page records the trusted-space migration ledger; the Q4 2025 entry’s BytecodeArray landing and the Q1 2026 entry’s WasmInstanceObject milestone are the two most consequential public events documenting the partition’s current state. Samuel Groß’s OffensiveCon 2024 presentation “The V8 Heap Sandbox” (saelo.github.io / presentations) supplies a security-research-audience walkthrough of the partition’s design and threat model; the deck is the canonical secondary source for the trusted-pointer-table’s tag-check geometry. The Mem2019 HITCON 2024 disclosure “Breaking V8 Sandbox with Trusted Pointer Table” is an attacker’s-eye-view of the partition that shows what the trusted boundary defends against; it documents the AddSmi.ExtraWide byte-injection class that motivated the BytecodeArray migration. The V8CTF rules and the public V8CTF submission archive on github.com/google/security-research supply the operational record of which bypass shapes the partition has held against and which it has not.
Technical Drill-Down
- V8 Sandbox README — the V8 contributor’s reference for the partition’s structure, the trusted pointer table’s tag-check rules, and the trusted-space migration roadmap.
v8/src/sandbox/trusted-pointer-table.h— the tagged-pointer-table implementation; the tag-check geometry and the slot layout are documented in the header comments.- v8.dev: The V8 Sandbox, Samuel Groß, April 2024 — the design’s public introduction; trusted space and the trusted pointer table appear in the architectural overview.
- Chromium Security Quarterly Updates — the trusted-space migration ledger; BytecodeArray (Q4 2025) and WasmInstanceObject (Q1 2026) are the two most consequential entries.
- Samuel Groß: The V8 Heap Sandbox, OffensiveCon 2024 slides — the security-research-audience walkthrough of the partition’s design and threat model.
- Mem2019: Breaking V8 Sandbox with Trusted Pointer Table, HITCON 2024 — the attacker’s-eye-view of the trusted boundary and the
AddSmi.ExtraWidebyte-injection class that motivated the BytecodeArray migration. - V8CTF rules and submission archive — the operational record of which bypass shapes the partition has held against; useful as a calibration source on residual exposure.