# A Bug's Life: CVE-2021-21225

V8 Array.prototype.concat OOB read via TypedArray valueOf callback during CreateDataProperty, enabling renderer code execution in Chrome.

- Payout: $22,000
- Severity: high
- Program: Google
- Credited: Brendon Tiszka
- Disclosed: 2021-08-16
- CVE: CVE-2021-21225
- Write-up quality: 9/10
- Original: https://tiszka.com/blog/CVE_2021_21225.html
- Library page: https://bugbountylibrary.com/r/blog%3Atiszka-com-blog-cve-2021-21225-html
- Tags: domain:browser impact:data-leak impact:rce kind:bounty platform:blog sev:high tech:chromium technique:incomplete-fix technique:regression technique:source-review vuln:info-disclosure vuln:memory-corruption

**Target:** V8 Array.prototype.concat builtin in Chrome renderer
**Root cause:** IterateElements caches fast_length then calls visitor->visit which, for TypedArray storage, invokes Object::ToNumber on element values, triggering user valueOf callbacks that can shrink the array and GC it, leaving elements->get(j) reading out of bounds.
**Steps:**
1. Create `let u32 = new Uint32Array(32); u32.__defineSetter__('length', function(){});`
2. Define `class MyArray extends Array { static get [Symbol.species]() { return function(){ return u32; } } }`
3. Instantiate `var w = new MyArray(100);`
4. Store `w[1] = { valueOf: function(){ w.length = 1; gc(); return 1; } };`
5. Call `Array.prototype.concat.call(w)` to trigger valueOf during visitor->visit
6. Read OOB pointer values from returned TypedArray
**How found:** Tracked the history of prior concat bugs (CVE-2016-1646, CVE-2017-5030) caused by callbacks inside IterateElements; after TC39 made TypedArray elements configurable, re-examined the CreateDataProperty call graph and found Object::SetDataProperty calls Object::ToNumber on TypedArray values, reintroducing a callback path.
**Exploitation:** Symbol.species returns a TypedArray as the concat result; storing an object with valueOf into the input array causes Object::ToNumber to run the callback mid-loop, shrinking/GCing the backing store so subsequent elements->get(j) reads leak heap pointers, later used for code execution in the renderer.
**Escalation:** OOB read of heap pointers used as info leak toward full renderer code execution; works in pdfium, web workers, JIT-less environments.
**Insight:** When a spec change makes previously-immutable elements configurable, re-audit every abstraction (CreateDataProperty/SetDataProperty) that now reaches that type; look for implicit ToNumber/ToPrimitive conversions on the write path as callback injection points inside cached-length loops.
