# Prototype Pollution via parse() in NodeJS flatted

flatted's parse() uses attacker-controlled string keys as array indices, so "__proto__" resolves to Array.prototype and leaks a live reference enabling prototype pollution.

- Payout: Research
- Severity: high
- Program: flatted
- Found by: yohannslm
- Disclosed: 2026-03-19
- CVE: CVE-2026-33228
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-rf6f-7fwh-wjgh
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-rf6f-7fwh-wjgh
- Tags: area:oss domain:oss impact:dos impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:prototype-pollution

**Target:** npm library flatted parse() deserializer (esm/index.js, cjs/index.js)
**Root cause:** The resolver indexes the internal input Array with unvalidated string keys from parsed JSON; the non-numeric key "__proto__" traverses the prototype chain to Array.prototype, which passes the typeof-object and not-yet-parsed guards and is assigned as a parsed value.
**Steps:**
1. `const Flatted = require('flatted');`
2. `const parsed = Flatted.parse('[{"x":"__proto__"}]');`
3. `parsed.x.polluted = 'pwned';`
4. `console.log([].polluted);` // true
**How found:** Code reading of the resolver: noticed `input[value]` uses attacker-controlled string keys against a plain Array without numeric validation, then reasoned that "__proto__" resolves via the prototype chain to Array.prototype and passes the typeof/parsed guards.
**Exploitation:** Attacker supplies a crafted flatted string to parse(); the returned object holds a live reference to Array.prototype at the attacker-chosen property. Any downstream code writing to that property pollutes the global prototype, potentially causing DoS or code execution.
**Insight:** When a deserializer indexes an internal Array with untrusted string keys, test non-numeric keys like "__proto__" and "constructor": inherited getters return real objects that slip past `typeof === 'object'` and dedup guards, leaking prototype references into output.

## Proof of concept (copied exactly from the original report)

**Node PoC polluting Array.prototype via parse**

```
const Flatted = require('flatted'); 
  const parsed = Flatted.parse('[{"x":"__proto__"}]');
  parsed.x.polluted = 'pwned';
  console.log([].polluted);  // Returns true
```

