npm package report

Is nanoid safe?

5 known vulnerabilities, worst severity HIGH.

// reach

1 direct dependencies

none carry a known advisory

    286 packages depend on it

    an advisory here reaches each of them

    Create a free accountfor every dependency path, dependent and what to upgrade
    // ai model usage

    Tracked for PyPI packages. HuggingFace models declare Python dependencies, so npm packages are not covered.


    cvss
    7.4
    high

    CVSS v3.1 base score out of 10

    epss
    0.30%
    low

    chance of exploitation in 30 days, 22nd percentile of all CVEs

    xyz score
    4.8
    medium

    CyberXYZ composite out of 10

    fig. 01 — GHSA-xwg4-73v4-xw9w, the advisory selected below

    // 5 advisories

    GHSA-xwg4-73v4-xw9w

    HIGHGitHub ratingCVE-2026-73086
    // 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
    // cvss v3.1 vector

    CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

    Attack vector
    Network
    Attack complexity
    High
    Privileges required
    None
    User interaction
    None
    Scope
    Unchanged
    Confidentiality
    High
    Integrity
    High
    Availability
    None

    Checked 2026-11-06 at 21:01 UTC. The most recent advisory here was published 2026-09-01. Updated continuously from NVD, GHSA, OSV and CNA feeds.

    Think a verdict here is wrong? Tell us — we respond within 2 business days.