{"id":"GHSA-rf6f-7fwh-wjgh","summary":"Prototype Pollution via parse() in NodeJS flatted","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, $) =\u003e output =\u003e {\n    for (let ke = keys(output), {length} = ke, y = 0; y \u003c 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 \u003e= 0 && idx \u003c input.length)\n    ? input[idx]\n    : undefined;","aliases":["CVE-2026-33228"],"modified":"2026-07-17T21:16:14.681618560Z","published":"2026-03-19T17:43:54Z","database_specific":{"cwe_ids":["CWE-1321"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-03-19T17:43:54Z","nvd_published_at":"2026-03-20T23:16:46Z"},"references":[{"type":"WEB","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":"WEB","url":"https://github.com/WebReflection/flatted/commit/885ddcc33cf9657caf38c57c7be45ae1c5272802"},{"type":"PACKAGE","url":"https://github.com/WebReflection/flatted"},{"type":"WEB","url":"https://github.com/WebReflection/flatted/releases/tag/v3.4.2"}],"affected":[{"package":{"name":"flatted","ecosystem":"npm","purl":"pkg:npm/flatted"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.4.2"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 3.4.1","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-rf6f-7fwh-wjgh/GHSA-rf6f-7fwh-wjgh.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P"}]}