{"id":"CVE-2026-33228","aliases":["GHSA-rf6f-7fwh-wjgh"],"url":"https://o3.security/vulnerability/CVE-2026-33228","summary":"flatted: Prototype Pollution via parse()","details":"---\n  **Summary**\n\n  The parse() function in flatted can use attacker-controlled string values from the parsed JSON as direct array index\n  keys, without validating that they are numeric. Since the internal input buffer is a JavaScript Array, accessing it\n  with the key \"\\_\\_proto\\_\\_\" returns Array.prototype via the inherited getter. This object is then treated as a legitimate\n   parsed value and assigned as a property of the output object, effectively leaking a live reference to Array.prototype\n   to the consumer. Any code that subsequently writes to that property will pollute the global prototype.\n\n  ---\n  **Root Cause**\n\n  File: esm/index.js:29 (identical in cjs/index.js)\n```\n  const resolver = (input, lazy, parsed, $) => output => {\n    for (let ke = keys(output), {length} = ke, y = 0; y < length; y++) {\n      const k = ke[y];\n      const value = output[k];    \n      if (value instanceof Primitive) {\n        const tmp = input[value];      // Bug is here\n```\n\nNo validation that value is a safe numeric index input is built as a plain Array. JavaScript's property lookup on arrays traverses the prototype chain for non-numeric  keys. The key \"\\_\\_proto\\_\\_\" resolves to Array.prototype, which:\n\n  - has type \"object\" → passes the typeof tmp === object guard at line 30\n  - is not in the parsed Set yet → passes the !parsed.has(tmp) guard.\n  - The reference to Array.prototype is then enqueued in lazy and later unconditionally assigned to the output object.\n  ---\n  **Replication Steps**\n```\n  const Flatted = require('flatted'); \n  const parsed = Flatted.parse('[{\"x\":\"__proto__\"}]');\n  parsed.x.polluted = 'pwned';\n  console.log([].polluted);  // Returns true\n``` \n ---\n  **Impact**\n An attacker can supply a crafted flatted string to parse() that causes the returned object to hold a live reference to Array.prototype, enabling any downstream code that writes to that property to pollute the global prototype chain, potentially causing denial of service or code execution.\n\n  **Recommended solution**\n Validate that the index string represents an integer within the bounds of input before accessing it:\n\n  // Before (vulnerable)\n  const tmp = input[value];\n\n  // After (safe)\n  const idx = +value;  // coerce boxed String → number\n  const tmp = (Number.isInteger(idx) && idx >= 0 && idx < input.length)\n    ? input[idx]\n    : undefined;","published":"2026-03-20T23:06:48.485Z","modified":"2026-09-08T03:46:34.026988449Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"flatted","fixedVersion":"3.4.2"}],"fix":{"url":"https://github.com/WebReflection/flatted/commit/885ddcc33cf9657caf38c57c7be45ae1c5272802","label":"WebReflection/flatted@885ddcc"},"references":[{"type":"WEB","url":"https://github.com/WebReflection/flatted/releases/tag/v3.4.2"},{"type":"WEB","url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-33228.json"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:13826"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:34342"},{"type":"ADVISORY","url":"https://access.redhat.com/errata/RHSA-2026:9742"},{"type":"ADVISORY","url":"https://access.redhat.com/security/cve/CVE-2026-33228"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33228.json"},{"type":"ADVISORY","url":"https://github.com/WebReflection/flatted/security/advisories/GHSA-rf6f-7fwh-wjgh"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33228"},{"type":"REPORT","url":"https://bugzilla.redhat.com/show_bug.cgi?id=2449872"},{"type":"FIX","url":"https://github.com/WebReflection/flatted/commit/885ddcc33cf9657caf38c57c7be45ae1c5272802"},{"type":"PACKAGE","url":"https://github.com/WebReflection/flatted"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-08T03:46:34.026988449Z"}}