Local reproduction and weaponization of the V8 JS-to-Wasm deoptimization type confusion described by Nebula, taken to a xcalc popped from the renderer of Chrome for Testing 146.0.7680.165 (the bug is fixed in 147.0.7727.101).

All payloads are benign (a calculator / exit(0x42) / jmp $). Everything runs against a deliberately outdated browser in a local lab do not point it at anyone else.

Demo

https://github.com/user-attachments/assets/d450f064-ba52-4f39-a88b-367f31217143

The bug

JSToWasmFrameStateFunctionInfo's equality operator omits the Wasm signature comparison, so CSE/GVN merges frame states that differ only in signature. A lazy deopt then materializes a Wasm i64 as a tagged externref (and vice-versa), giving a full 64-bit addrof/fakeobj whose pointers are not cage-compressed (Wasm refs use the tagged register representation, returned via kReturnRegister0).

Everything below was verified live against 146.0.7680.165. Per-load numbers are measured hit-rates over repeated runs (the confusion is GC-sensitive; each page relaunches on a dirty build). No run ever produced a false positive.

Flag-free primitives — no --allow-natives-syntax

Most V8 bug PoCs force optimization with %OptimizeFunctionOnNextCall, a test-only intrinsic gated behind --allow-natives-syntax that no real victim enables. These drive the bug with no flags at all, by shaping the warmup feedback so the deopt confusion fires naturally. Every address is leaked at runtime — nothing is hardcoded. Run them headless with no flags.

File Proves Verified
flag-free/00-reachability-flagfree.html triggers the confused state; fires on vulnerable 146, not on patched 147 6/15 per load
flag-free/01-primitives-flagfree.html addrof / fakeobj (fakeobj(addrof(o))===o) 8/12
flag-free/02-store-flagfree.html out-of-cage store lands a chosen value in a chosen object 12/12
flag-free/03-arw-flagfree.html in-cage read64 / write64 (fake PACKED_DOUBLE array) 2/12 (flaky, retry)

Visible RCE — no-ASLR lab build

rce-no-aslr/ takes it to code execution: an optimized JS function g stages execve shellcode as JIT double-literals (movabs constants, each ending in eb rel8 to chain the next), the confused store patches a nop; jmp into g's code, and calling g() slides RIP into the shellcode.

File Proves Verified
rce-no-aslr/exploit-calc.html pops a real xcalc window via execve from the renderer pops in ~1s on a clean slate
rce-no-aslr/exploit-exit.html renderer runs the injected shellcode to exit(66); #jmp spins RIP inside it exit(66) 8/8 (strace)

This build uses --allow-natives-syntax (%Optimize pins g's JIT payload so the deopt-GC can't flush it) and --no-memory-protection-keys (so the confused store can patch the JIT page — V8's PKU marks it read-only otherwise). ASLR is off (randomize_va_space=0) so the addresses are deterministic (A_MAP = 0x5555bbc0128a). The renderer also needs --disable-seccomp-filter-sandbox --no-zygote, because seccomp otherwise blocks the shellcode's execve.

Run it

Native x86_64 Linux, ASLR off, Chrome 146 on PATH, an X display on :0 (Xvfb or real X). rce-no-aslr/run.sh sets all the flags and serves over http.

cd rce-no-aslr
./run.sh calc          # pop a real xcalc over http://127.0.0.1:8080, on :0
./run.sh exit          # strace-confirms the renderer's exit(66)
./run.sh jmp           # gdb-confirms RIP inside the injected shellcode
./demo.sh calc            # clean-slate + auto-retry, full-size headful browser (for recording)
./demo.sh msgbox          # same, but the pop is a branded "0xSha :: pwned" box

pocmode.sh calc|msgbox switches what the RCE's execve("/usr/bin/xcalc") launches (a real calculator vs the branded box). The flag-free primitives just need a browser:

chrome --headless=new --no-sandbox http://127.0.0.1:8080/flag-free/01-primitives-flagfree.html

Layout

flag-free/   the no-flags contribution (NO --allow-natives-syntax)
  00-reachability   trigger + patch differential (vuln 146 vs patched 147)
  01-primitives     addrof / fakeobj
  02-store          out-of-cage store
  03-arw            in-cage read64 / write64
rce-no-aslr/ the visible RCE (deterministic, no-ASLR lab build)
  exploit-calc.html / exploit-exit.html
  run.sh, demo.sh, pocmode.sh, xcalc-msgbox.sh

Bug and root-cause writeup: Nebula Security (linked above). Flag-free trigger, primitives, and the visible works in this repo are reproductions/extensions verified in a local lab.