---
id: CVE-2026-59880
aliases:
  - GHSA-xvcm-6775-5m9r
title: >-
  Immutabl: Hash-collision algorithmic complexity denial of service in
  Immutable.Map/Set
summary: >-
  Immutabl: Hash-collision algorithmic complexity denial of service in
  Immutable.Map/Set
severity: high
cwe:
  - CWE-400
  - CWE-407
vendor: immutable
product: immutable
ecosystem: npm
affected:
  - immutable < 4.3.9
  - 'immutable >= 5.0.0-beta.1, < 5.1.8'
patched:
  - immutable 4.3.9
  - immutable 5.1.8
published: '2026-07-21'
updated: '2026-07-21'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-xvcm-6775-5m9r'
references:
  - url: >-
      https://github.com/immutable-js/immutable-js/security/advisories/GHSA-xvcm-6775-5m9r
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-59880'
  - url: >-
      https://github.com/immutable-js/immutable-js/commit/3dd7e5655012597a41873e328bf9142a8901527b
  - url: >-
      https://github.com/immutable-js/immutable-js/commit/e51d49fc612ded5ec4dfb94ff294d22074269b0f
  - url: 'https://github.com/immutable-js/immutable-js/releases/tag/v4.3.9'
  - url: 'https://github.com/immutable-js/immutable-js/releases/tag/v5.1.8'
  - url: 'https://github.com/advisories/GHSA-xvcm-6775-5m9r'
tags:
  - ghsa
  - npm
epss: 0.00665
epssPercentile: 0.49605
ingestedAt: '2026-07-21T19:53:40.243Z'
---

## Overview

## Summary

`Immutable.Map` and `Immutable.Set` keep keys that share the same 32-bit hash in a collision bucket that is scanned linearly. The string hash is public and deterministic, so an attacker who controls the **keys** inserted into a Map can craft many keys that all collide, degrading insertion and lookup from amortized O(1) to O(n) per operation — and O(n²) to build or read the whole set. A small, attacker-shaped payload can therefore consume disproportionate CPU and, on a single-threaded runtime such as Node.js, stall the event loop and deny service.

## Details

The string hash uses the JVM-style polynomial `hashed = (31 * hashed + charCode) | 0`. Strings such as `"Aa"` and `"BB"` hash to the same value (`65*31+97 == 66*31+66 == 2112`), and concatenating such blocks yields `2^n` distinct strings sharing one hash (40 characters ⇒ >1,000,000 colliding keys). 
All such keys route to a single `HashCollisionNode`, whose `get`/`update` walk the entire bucket testing `is()`. There is no per-process salt, so the colliding set is fully precomputable from the open-source algorithm.

## Proof of concept

Inserting N colliding keys (e.g. via `Immutable.Map(obj)` / `Immutable.fromJS(obj)`) is O(N²). Measured on one machine, ~8,000 colliding
keys take ~0.7 s to build and ~0.6 s to read, scaling ×4 per doubling; ~16,000 keys exceed several seconds.

## Impact

CPU-bound denial of service in applications that ingest attacker-controlled object **keys** into Immutable structures, e.g. `Immutable.Map(req.body)`, `Immutable.fromJS(req.body)`, `state.merge(userObject)` / `mergeDeep(...)`. Applications that only store attacker input as **values** under fixed keys are not affected.

## Affected versions

All versions through `5.1.7` (the deterministic string hash and linear collision bucket have existed since the 4.x line).

## Patches

Fixed in `5.1.8` _(adjust to the actual release)_: large collision buckets are indexed by a per-process **seeded** secondary hash, restoring near-linear behavior for the affected paths. The public `hash()` is unchanged (no breaking change), and `is()` remains the sole authority on key equality.

## Workarounds

Before passing untrusted data to Immutable.js: cap request body size, limit object key count/length, and reject high-cardinality payloads; avoid building Maps directly from untrusted object keys.

## References

- CWE-407 (Inefficient Algorithmic Complexity), CWE-400 (Uncontrolled Resource Consumption)
- OWASP API4:2023 (Unrestricted Resource Consumption)

## Affected packages

- `immutable < 4.3.9`
- `immutable >= 5.0.0-beta.1, < 5.1.8`

## Remediation

Upgrade to a patched release:

- `immutable 4.3.9`
- `immutable 5.1.8`
