# Exploitation Of CVE-2021-21220 – From Incorrect JIT Behavior To RCE

Incorrect JIT numeric result in V8 lets Array.shift underflow length to -1, giving OOB access and RCE in Chrome/Edge.

- Payout: $100,000
- Severity: high
- Program: Google, Microsoft
- Credited: Bruno Keith, Niklas Baumstark
- Disclosed: 2021-12-16
- CVE: CVE-2021-21220
- Write-up quality: 8/10
- Original: https://www.zerodayinitiative.com/blog/2021/12/15/exploitation-of-cve-2021-21220-from-incorrect-jit-behavior-to-rce
- Library page: https://bugbountylibrary.com/r/blog%3Azerodayinitiative-com-blog-2021-12-15-exploitation-of-cve-2021-21220-from-incorrect-jit-behavior-to-rce
- Tags: domain:browser impact:rce kind:bounty platform:blog sev:high tech:chromium technique:chained technique:source-review vuln:memory-corruption vuln:rce

**Target:** V8 JavaScript engine JIT (Array.prototype.shift reduction)
**Root cause:** JIT produces an incorrect numeric result, and the ArrayPrototypeShift reduction blindly subtracts 1 from a length the engine believes is zero, underflowing to -1 and bypassing unsigned bounds checks.
**Steps:**
1. Trigger CVE-2021-21220 so a variable holds a huge incorrect value; pass through `Math.max` calls to confuse it down to 1.
2. Create an array with this confused length and call `shift` on it, producing an array with length -1.
3. Use the length -1 array to OOB-write and enlarge lengths of adjacent `after_dbl` (PACKED_DOUBLE_ELEMENTS) and `after_obj` (PACKED_ELEMENTS) arrays.
4. Build `addrof` by storing an object at `after_obj[0x2f]` and reading the overlapping `after_dbl2` as a double.
5. Build `fakeobj` by writing a pointer into `after_dbl` and reading it back through overlapping `after_obj`.
6. Leak a wasm function address via `addrof`; its page is RWX.
7. Forge an ArrayBuffer/array with arbitrary backing store via `fakeobj` and copy shellcode over the wasm function instructions.
8. Call the wasm function to execute shellcode; smooth corruptions to survive GC.
**How found:** Researcher traced the ArrayPrototypePop/Shift OOB technique back through Chromium bug tracker entries from late 2020, noting that with bounds-check elimination removed, the shift reduction's length-1 subtraction could underflow if JIT yields a wrong zero length.
**Exploitation:** At Pwn2Own, exploit chains the JIT miscomputation into an Array.shift length underflow, uses the resulting OOB to corrupt adjacent array lengths, builds addrof/fakeobj, leaks a wasm function's RWX address, overwrites it with shellcode via a forged backing store, and calls the wasm function for code execution in the renderer.
**Escalation:** Chained JIT numeric bug -> OOB -> array length corruption -> addrof/fakeobj -> arbitrary R/W -> RWX wasm overwrite -> RCE; used to exploit both Chrome and Edge.
**Insight:** When bounds-check elimination is hardened away, look at other JIT reductions of builtins (shift/pop) that do arithmetic on a length the typer believes is constant; a wrong zero length turns `len-1` into -1 and unsigned checks pass.
