Skip to main content
Press slash or control plus K to focus the search. Use the arrow keys to navigate results and press enter to open a threat.
Reconnecting to live updates…
EPSS 0.7%top 51%

Immutable.js `List` 32-bit trie overflow → unrecoverable DoS (CVE-2026-59879)

0
High
Published: 07/21/2026 (07/21/2026, 18:36:27 UTC)
Source: GCVE Database
Product: immutable

Description

## Summary `List#set`, `List#setSize`, `List#setIn`, `List#updateIn` (and the functional `set` / `setIn` / `updateIn`) mishandle an index or size in the range `[2 ** 30, 2 ** 31)`: - On an **empty** `List` the operation enters an **uncatchable infinite loop** (a tight CPU spin; a surrounding `try/catch` never regains control). Only killing the worker recovers it. - On a **populated** `List` (≥ 32 elements — i.e. any array of ≥ 32 items turned into a `List` by `fromJS`) the loop allocates without bound → heap exhaustion → the **process aborts** (`SIGABRT`, exit `134`, or kernel OOM-kill `137`). A real crash, not a recoverable error. The index may be a **numeric string**, so it can come straight from a request body, URL, or key-path. A single small unauthenticated request is enough. There is also a companion **silent data-corruption** issue in `setSize`: ```js List([1, 2, 3]).setSize(2 ** 31); // before fix => size 0 (silently cleared) List([1, 2, 3]).setSize(2 ** 32 + 5); // before fix => size 5 (huge value wraps to 5) ``` ## Impact Availability only. A reachable configuration is any endpoint that routes untrusted input into a `List` index or a `setIn`/`updateIn` key-path — which the extremely common `state = fromJS(body); state.setIn(userPath, value)` pattern does (config stores, document/collection editors, redux-immutable reducers, JSON-Patch endpoints, etc.). No confidentiality or integrity impact, no RCE. The companion `setSize` bug can silently corrupt application state (wrong size) without crashing. ## Reproduction (immutable 5.1.7) ```ts import { fromJS, List } from 'immutable'; // 1) Populated List: OOM -> process abort (SIGABRT, exit 134) within ~2s fromJS({ items: new Array(64).fill(0) }).setIn(['items', '1073741824'], 'x'); // 2) Empty List: hangs forever, uncatchable List().set(2 ** 30, 'x'); // 3) Silent truncation List([1, 2, 3]).setSize(2 ** 31); // => size 0 List([1, 2, 3]).setSize(2 ** 32 + 5); // => size 5 ``` A remote 43-byte HTTP request (`{"path":["items","1073741824"],"value":"x"}`) is sufficient to abort a worker that applies it via `state = state.setIn(path, value)`. Any index in `[2 ** 30, 2 ** 31)` works (`1073741824`, `2000000000`, …). An index in `[2 ** 31, 2 ** 32)` does not crash — it silently wraps (clearing the List) via the same root cause. ## Root cause `List` stores its values in a 32-wide trie (`SHIFT = 5`, so each level addresses 5 more bits) and uses **signed 32-bit bitwise arithmetic** throughout `setListBounds()` (`src/List.js`): 1. **Infinite loop (the hang / OOM).** The level-raising loop ```js while (newTailOffset >= 1 << (newLevel + SHIFT)) { newRoot = new VNode( newRoot && newRoot.array.length ? [newRoot] : [], owner ); newLevel += SHIFT; } ``` relies on `1 << (newLevel + SHIFT)`. A JavaScript shift count is taken **mod 32**, so once `newLevel + SHIFT` reaches `31` the term goes **negative** (`1 << 31 === -2147483648`) and at `32` wraps to `1` (`1 << 35 === 8`). The comparison then stays `true` forever and the loop never terminates. On a populated `List`, each iteration retains a new `VNode` (`[newRoot]`), so the heap fills and V8 aborts; on an empty `List` it spins on CPU without allocating. 2. **Silent wraparound (the `setSize` corruption).** The `begin |= 0` / `end |= 0` coercion (`ToInt32`) silently wraps large finite values (`(2 ** 31) | 0 === -2147483648`, `(2 ** 32 + 5) | 0 === 5`), producing a wrong resulting size instead of an error. The threshold is `2 ** 30`: that is the largest size for which `1 << (newLevel + SHIFT)` stays a valid positive 32-bit integer throughout the loops (`newLevel + SHIFT` stays ≤ 30). ## Remediation The fix is contained to `setListBounds()` in `src/List.js`: 1. **Validate up front, before the lossy `| 0` coercion.** Compute the intended origin and capacity in full precision and throw a clear, catchable `RangeError` when they exceed the addressable range (`MAX_LIST_SIZE = 2 ** 30`). `Infinity`/`NaN` are left to the existing `| 0 → 0` behaviour (so `setSize(Infinity)` stays `0` and `slice(0, Infinity)` still means "to the end"). 2. **Stop the shift from wrapping.** Replace `1 << exp` in the level-raising loops with a helper that uses the cheap bitwise shift while it is exact (`exp ≤ 30`, the common path including every `push`/`setSize`/`slice`) and falls back to the non-wrapping `2 ** exp` only for the rare deep trees reached when a negative origin (`unshift` / negative index) is normalized to a large positive capacity (`exp` can reach 35 there, where `1 << 35` would wrap to 8). This turns every hang, the misleading `"Maximum call stack size exceeded"`, the OOM/`SIGABRT`, and the silent `setSize` truncation into one descriptive `RangeError`, preserves all behaviour for sizes `< 2 ** 30`, and keeps the hot `push` path on the fast bitwise shift (the `2 ** exp` branch is never reached by non-negative operations). ### Is the new limit a breaking change? No working code is affected. A `List

CVSS v4.0

Attack Vector
Network
Attack Complexity
Low
Attack Requirements
None
Privileges Required
None
User Interaction
None
Vuln. Confidentiality
None
Vuln. Integrity
None
Vuln. Availability
High
Subsq. Confidentiality
None
Subsq. Integrity
None
Subsq. Availability
None
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Affected software

npmghsa
immutable
Affected versions
<4.3.9
npmghsa
immutable
Affected versions
>=5.0.0-beta.1 <5.1.8

Run on your own infrastructure? Check whether these packages are installed with threat-finder — our free open-source scanner.

AI-Powered Analysis

Machine-generated threat intelligence

AILast updated: 07/21/2026, 20:35:54 UTC

Technical Analysis

The vulnerability in Immutable.js List arises from the use of signed 32-bit bitwise arithmetic in the internal 32-wide trie implementation. Operations like set, setIn, updateIn, and setSize mishandle indices or sizes ≥ 2^30 due to JavaScript's 32-bit shift behavior causing infinite loops or heap exhaustion. On empty Lists, this results in an infinite CPU spin that cannot be caught by try/catch. On populated Lists, it causes unbounded memory allocation leading to process aborts (SIGABRT or OOM kills). The setSize method also silently corrupts List size by wrapping large values due to coercion to 32-bit integers. The root cause is a loop relying on 1 << (newLevel + SHIFT) which wraps and causes the loop to never terminate. The fix involves upfront validation to throw RangeErrors for sizes exceeding 2^30 and replacing the shift operation with a safe non-wrapping alternative. This vulnerability affects versions before 4.3.9.

Potential Impact

This vulnerability impacts availability by causing denial of service through infinite loops or process crashes when untrusted input controls List indices or key-paths. It can be triggered remotely with a small unauthenticated request. There is no impact on confidentiality, integrity, or remote code execution. The companion setSize issue can silently corrupt application state by incorrectly resizing Lists without crashing.

Mitigation Recommendations

A fix is available in Immutable.js version 4.3.9 and later. Users should upgrade to version 4.3.9 or newer to prevent this vulnerability. The fix adds upfront validation to reject indices or sizes exceeding 2^30 with a catchable RangeError and replaces unsafe bitwise shifts with safe computations to prevent infinite loops and memory exhaustion. Until upgrading, avoid passing untrusted input as List indices or key-paths in affected methods. Patch status is confirmed by the vendor advisory indicating the fix in version 4.3.9.

Pro Console: star threats, build custom feeds, automate alerts via Slack, email & webhooks.Upgrade to Pro

Technical Details

Gcve Source
db.gcve.eu
Osv Id
GHSA-v56q-mh7h-f735
Osv Schema Version
1.4.0
Aliases
["CVE-2026-59879"]
Ecosystems
["npm"]
Database Specific Severity
HIGH
Cvss Version
4.0

Threat ID: 6a5fcf3c1010f89cc2151207

Added to database: 07/21/2026, 19:57:48 UTC

Last enriched: 07/21/2026, 20:35:54 UTC

Last updated: 08/26/2026, 19:42:25 UTC

Views: 59

Community Reviews

0 reviews

Crowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.

Sort by
Loading community insights…

Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.

Actions

PRO

Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.

Please log in to the Console to use AI analysis features.

Need more coverage?

Upgrade to Pro Console for AI refresh and higher limits.

For incident response and remediation, OffSeq services can help resolve threats faster.

Latest Threats

Breach by OffSeqOFFSEQFRIENDS — 25% OFF

Check if your credentials are on the dark web

Instant breach scanning across billions of leaked records. Free tier available.

Scan now
OffSeq TrainingCredly Certified

Lead Pen Test Professional

Technical5-day eLearningPECB Accredited
View courses