A shared cookie jar that nobody asked for — undici's opt-in cache happily serves one user's session to the next
CVE-2026-84933 affects undici versions 7.0.0 – 7.29.0 and 8.0.0 – 8.10.1. The cache interceptor, when enabled in shared mode (the default *when the interceptor is active*), stores HTTP responses without stripping or rejecting Set-Cookie headers. A cacheable response carrying Set-Cookie — e.g. one with Cache-Control: public, max-age=3600 — gets stored verbatim and replayed to every subsequent caller whose request matches the same cache key. The result is cross-user cookie disclosure: caller B receives caller A's session cookie, and an attacker-controlled upstream can inject arbitrary cookies into all downstream consumers.
The vendor rates this MEDIUM / 6.5 with AC:H, and that rating is *defensible*. The single most important friction point is that the cache interceptor is opt-in — it is not enabled by default. A developer must explicitly compose the interceptor via setGlobalDispatcher(getGlobalDispatcher().compose(interceptors.cache())). Despite undici's massive install base (~175 million weekly npm downloads), the fraction of deployments that enable the cache interceptor in shared mode is small — likely single-digit percent. For those that do, the impact is real: session hijack, cookie injection, and potential auth bypass in multi-tenant Node.js services. But the AC:H vector and opt-in gating make 6.5 a fair ceiling; noisgate trims it to 5.5 for the opt-in friction.
4 steps from start to impact.
Upstream returns Set-Cookie with cacheable directives
Set-Cookie header and Cache-Control: public, max-age=<N>. Alternatively, a legitimate upstream may unintentionally combine these headers, which is uncommon but not unheard of in misconfigured CDN origins.- Attacker controls or can influence at least one upstream origin
- Upstream response includes Set-Cookie alongside cacheable Cache-Control directives
- Most legitimate origins do not combine Set-Cookie with public cache directives
- MITM requires a separate position on the network or DNS compromise
Undici cache interceptor stores response with Set-Cookie intact
Set-Cookie, the full response — including the session cookie — is written to the cache store (in-memory, SQLite, or Redis). The cache key is derived from the request method, URL, and Vary headers. No special conditions beyond the interceptor being enabled are needed.- Cache interceptor explicitly enabled via
interceptors.cache() - Shared cache mode (default when interceptor is active)
- Cache interceptor is opt-in — most undici consumers never enable it
- Developers using private cache mode (
type: 'private') are not affected in the same cross-user way
Second caller receives first caller's cookie
Set-Cookie header from user A's session. User B's HTTP client or browser now sets the cookie, effectively assuming user A's session. In a server-side proxy or SSR framework, user B's response is sent downstream with user A's cookie baked in.- A second request matches the same cache key before TTL expiry
- The application does not independently strip Set-Cookie from cached responses
- Cache key collision requires same method + URL + Vary-matched headers
- Short max-age values reduce the exploitation window
Session hijack or cookie injection
- Application relies on cookies for authentication or authorization
- No additional session-binding (e.g. IP pinning, device fingerprinting) is enforced
- Modern frameworks often use token-based auth (JWT in Authorization header) rather than cookies for API-to-API calls
- Server-side undici callers are less likely to honor Set-Cookie than browser-based flows
type: 'private' in the interceptor options or disable the interceptor entirely until you can upgrade. This eliminates the cross-user disclosure vector. No noisgate mitigation SLA applies (MEDIUM verdict), so go straight to the 365-day remediation window, but this is a one-line config change worth making immediately.Set-Cookie header from responses before they enter the cache. This replicates what the patch does.Set-Cookie with Cache-Control: public. This is an HTTP best-practice violation regardless of this CVE.- WAF rules — This is an application-layer caching logic bug inside the Node.js process. No network-level WAF can inspect or modify undici's internal cache store behavior.
- CDN-level Set-Cookie stripping — Stripping Set-Cookie at the CDN edge does not help because undici's cache interceptor operates on the origin response *after* the CDN, inside the Node.js process.
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed on CISA KEV. No known campaigns as of 2026-09-05. |
|---|---|
| Proof of Concept | No public PoC. The advisory describes the mechanism in sufficient detail to reproduce in a test harness, but no standalone exploit repo has been published. |
| EPSS Score | Not yet scored — CVE disclosed 2026-09-04; EPSS data typically populates within 7–14 days of NVD publication. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-09-05. |
| CVSS Vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N — Network-accessible, high attack complexity, no privileges or user interaction needed. High confidentiality impact (cookie disclosure), low integrity impact (cookie injection), no availability impact. |
| Affected Versions | undici 7.0.0 – 7.29.0 and 8.0.0 – 8.10.1. The cache interceptor was introduced in undici 7.0.0. |
| Fixed Versions | 7.29.1 and 8.10.2 — the fix strips Set-Cookie from responses before cache storage in shared mode. |
| Installed Base | undici has ~175 million weekly npm downloads. However, the cache interceptor is opt-in and not enabled by default, drastically limiting the exposed population. |
| Disclosure Date | 2026-09-04 via GitHub Security Advisory GHSA-4cwx-7wf7-3272 (covers related cache issues). |
| Reporter | Not publicly attributed in the advisory. |
Sources.
Why this verdict
- Opt-in friction is the dominant downgrade factor. The cache interceptor is not enabled by default in undici. A developer must explicitly compose it into the dispatcher chain. This transforms a 175M-download-base vulnerability into one affecting a small opt-in subset — likely <5% of installations.
- AC:H already baked in. The vendor's CVSS vector sets Attack Complexity to High, acknowledging that exploitation requires specific conditions (cacheable + Set-Cookie + matching cache key + shared mode). This is accurate.
- No exploitation signal. Zero KEV listing, zero known campaigns, no public PoC as of day-one disclosure. The practical risk to an enterprise scanning for this today is near zero.
- Role multiplier: (a) *Low-value role* — dev tooling, CLI scripts, test harnesses using undici: chain does not succeed because cache interceptor is almost never enabled. (b) *Typical role* — Node.js API server using undici as an HTTP client: chain succeeds only if cache interceptor is explicitly enabled in shared mode AND upstream sends Set-Cookie with cacheable directives. Blast radius is tenant-level (one service's users). (c) *High-value role* — Node.js reverse proxy / API gateway / SSR framework (e.g. Next.js, Nuxt) with undici shared caching enabled and serving multi-tenant authenticated traffic: blast radius is cross-user session hijack within that service. This is serious but bounded to the service, not fleet/domain/supply-chain scale. undici is not canonically infrastructure (not a hypervisor, IdP, PAM, CA, or network edge appliance), so the HIGH floor does not trigger.
Why not higher?
Upgrading to HIGH would require either active exploitation, a public weaponized PoC, or a blast radius that reaches fleet/domain/supply-chain scale. None of these conditions are met. The cache interceptor is opt-in, the attack complexity is high, and even in the worst case the blast radius is limited to cross-user disclosure within a single Node.js service — not lateral movement, domain takeover, or supply-chain compromise.
Why not lower?
Dropping to LOW would understate the impact for the deployments that *do* use shared caching. In those environments, cross-user session cookie disclosure is a genuine confidentiality breach that could enable account takeover. The CVSS C:H rating is warranted for affected deployments, and the network-accessible attack vector with no authentication requirement keeps a baseline of concern.
Crowdsourced verification payload.
Run this on any host where a Node.js application uses undici. It checks the installed undici version against the vulnerable ranges. Requires node and npm in PATH. No elevated privileges needed. Example: bash check_undici_cve_2026_84933.sh /path/to/your/node/project
#!/usr/bin/env bash\n# check_undici_cve_2026_84933.sh\n# Checks whether the installed undici version is vulnerable to CVE-2026-84933\n# Usage: bash check_undici_cve_2026_84933.sh [project_dir]\n# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN\n\nset -euo pipefail\n\nPROJECT_DIR=\"${1:-.}\"\n\nif [ ! -d \"$PROJECT_DIR/node_modules/undici\" ]; then\n echo \"UNKNOWN - undici not found in $PROJECT_DIR/node_modules/\"\n exit 2\nfi\n\nVERSION=$(node -e \"console.log(require('$PROJECT_DIR/node_modules/undici/package.json').version)\" 2>/dev/null)\n\nif [ -z \"$VERSION\" ]; then\n echo \"UNKNOWN - could not read undici version\"\n exit 2\nfi\n\n# Parse major.minor.patch\nIFS='.' read -r MAJOR MINOR PATCH <<< \"$VERSION\"\n\nVULN=false\n\n# Check 7.0.0 - 7.29.0\nif [ \"$MAJOR\" -eq 7 ]; then\n if [ \"$MINOR\" -lt 29 ]; then\n VULN=true\n elif [ \"$MINOR\" -eq 29 ] && [ \"$PATCH\" -lt 1 ]; then\n VULN=true\n fi\nfi\n\n# Check 8.0.0 - 8.10.1\nif [ \"$MAJOR\" -eq 8 ]; then\n if [ \"$MINOR\" -lt 10 ]; then\n VULN=true\n elif [ \"$MINOR\" -eq 10 ] && [ \"$PATCH\" -lt 2 ]; then\n VULN=true\n fi\nfi\n\nif [ \"$VULN\" = true ]; then\n echo \"VULNERABLE - undici $VERSION is affected by CVE-2026-84933\"\n exit 1\nelse\n echo \"PATCHED - undici $VERSION is not affected by CVE-2026-84933\"\n exit 0\nfi