A vending machine that keeps dispensing yesterday's sandwich because nobody told it POST means 'make a new one'
CVE-2026-85008 is a logic flaw in undici's cache interceptor — a feature consumers must explicitly opt into. The interceptor documents that only safe HTTP methods (GET, HEAD) are cached, but the skip-list was built by *subtracting* configured methods from the safe set rather than *allow-listing* them. The result: unsafe methods like POST, PUT, and DELETE fall through to the cache-read path, and the storage gate never checks the method either. If a remote origin returns a response with an explicit Cache-Control directive (or a heuristically cacheable status like 404 max-age=60), undici stores and replays it for subsequent requests to the same path — even state-changing ones. Affected versions are undici 7.0.0–7.29.0 and 8.0.0–8.10.1, fixed in 7.29.1 and 8.10.2.
The vendor rates this LOW / 3.7 and that assessment is accurate. The CVSS vector (AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N) reflects the reality: the attack only touches integrity (no data leak, no crash), requires the attacker to *be* or *compromise* the origin the client talks to, and only fires when the cache interceptor is enabled — which is not the default. Despite undici's enormous install base (~150M+ weekly npm downloads), the fraction of deployments that activate the cache interceptor is small, and the fraction where the origin is untrusted is smaller still.
3 steps from start to impact.
Client enables cache interceptor
- Application code explicitly enables the cache interceptor
- Cache interceptor is not enabled by default — most undici consumers never touch it
- Requires developer intent; no silent activation path
Malicious origin serves cacheable response to unsafe method
Cache-Control: max-age=3600 header or a heuristically cacheable status (e.g., 200, 404). Because the storage gate lacks a method check, undici stores this response.- Attacker controls or has compromised the upstream origin
- Client issues unsafe HTTP method to a path the attacker controls
- If the attacker already controls the origin, they have far more powerful attack options than cache poisoning
- HTTPS/TLS prevents network-level MITM in standard deployments
Subsequent requests served from stale cache
- Subsequent request to the same path occurs before cache TTL expires
- Impact is limited to integrity of responses within the single client process — no cross-user or cross-tenant leakage
- Application-level validation or idempotency checks may catch stale responses
The supporting signals.
| In-the-wild exploitation | None observed. No known campaigns, no CISA KEV listing, no vendor emergency advisory. |
|---|---|
| Proof-of-concept | No public PoC exploit repository found. The advisory from MegaManSec (reporter) describes the logic flaw but no weaponized tooling. |
| EPSS score | Not yet scored (CVE disclosed 2026-09-04, EPSS model lag expected). Given AC:H and I:L, expect bottom decile once scored. |
| KEV status | Not listed on CISA KEV as of 2026-09-05. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N — network-reachable but high complexity, integrity-only impact, no scope change. |
| Affected versions | undici 7.0.0 – 7.29.0 and 8.0.0 – 8.10.1 |
| Fixed versions | undici 7.29.1 and 8.10.2 |
| Install base | ~150M+ weekly npm downloads (npmjs.com/package/undici). However, the cache interceptor is opt-in; exposed population is a small fraction of total installs. |
| Disclosure date | 2026-09-04 |
| Reporter / credits | MegaManSec (reporter); mcollina and UlisesGascon (remediation) |
noisgate verdict.
The single most decisive factor is that the cache interceptor is an opt-in feature disabled by default, which shrinks the reachable population to a small fraction of undici's install base. Combined with the requirement that the attacker must already control or compromise the upstream origin — a position that affords far more damaging attacks — the integrity-only, no-confidentiality, no-availability impact justifies LOW.
Why this verdict
- Opt-in feature gate: The cache interceptor is not enabled by default. Developers must explicitly register it. This alone eliminates the vast majority of undici's ~150M weekly download install base from the vulnerable population.
- Attacker must own the origin: The CVSS vector requires AV:N/AC:H. In practice the attacker must control or compromise the upstream server the client talks to. At that point, cache poisoning is a strictly weaker attack than the alternatives already available (serving arbitrary malicious responses directly).
- Integrity-only, single-process blast radius: Impact is limited to I:L — stale or crafted responses within one Node.js process. No confidentiality breach, no availability impact, no cross-user or cross-tenant leakage. The scope is Unchanged (S:U).
- Role multiplier: undici is a user-space HTTP client library in Node.js. (a) *Low-value role*: dev scripts, CLI tools — no meaningful blast radius. (b) *Typical role*: backend microservice making outbound API calls — integrity issue confined to one service's view of upstream data. (c) *High-value role*: CI/CD build pipelines or internal proxies using undici with cache interceptor against semi-trusted registries — theoretically a supply-chain concern, but requires both opt-in caching AND compromised origin, making real-world occurrence vanishingly rare. No canonical high-value-role deployment (this is not a hypervisor, IdP, DC, or network edge). Floor does not apply.
Why not higher?
The attack requires the cache interceptor to be explicitly enabled (opt-in), the attacker to already control the origin server, and delivers only an integrity impact with no confidentiality or availability consequences. There is no public PoC, no KEV listing, no in-the-wild exploitation, and no cross-boundary scope change. Elevating to MEDIUM would require at least one of: default-on exposure, broader impact category, or evidence of exploitation.
Why not lower?
The flaw is real and affects a widely-used library. While opt-in, the cache interceptor exists for a reason and some production deployments do use it. The integrity violation — silently serving stale responses to state-changing requests — can cause subtle, hard-to-diagnose application logic errors. IGNORE would understate the risk for the subset of applications that have opted in.
What to do — in priority order.
- Audit your codebase for cache interceptor usage — Search for
CacheInterceptor,interceptors.cache, orcacheInterceptorin your Node.js projects. If none are found, this CVE does not affect you. Complete this audit within your normal backlog cycle. - Upgrade undici to 7.29.1 or 8.10.2 — The fix adds a method check to both the cache-read and cache-write gates. For a LOW verdict there is no noisgate mitigation SLA — treat this as backlog hygiene and roll the upgrade into your next scheduled dependency update.
- Pin unsafe-method paths to no-cache if upgrading is delayed — If you cannot upgrade immediately, configure the cache interceptor's
methodsoption to explicitly list onlyGETandHEAD, or addCache-Control: no-storeheaders to outbound unsafe-method requests at the application layer.
- WAF / reverse proxy caching rules — This is a client-side cache bug, not a server-side cache poisoning issue. Your edge infrastructure has no visibility into undici's in-process cache.
- Network-level controls (firewall, IDS) — The cached responses travel over normal HTTPS connections; there is no network signature to detect or block.
Crowdsourced verification payload.
Run this on any host where your Node.js applications are deployed, or in your CI pipeline. Requires node (v18+) and read access to node_modules. Example: bash check_cve_2026_85008.sh /app
#!/usr/bin/env bash
# check_cve_2026_85008.sh — Detect undici versions vulnerable to CVE-2026-85008
# Usage: bash check_cve_2026_85008.sh [PROJECT_DIR]
# Exit codes: 0 = PATCHED/NOT_AFFECTED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
if [ ! -d "$PROJECT_DIR" ]; then
echo "UNKNOWN — directory $PROJECT_DIR does not exist"
exit 2
fi
# Find all undici installations
found=0
vulnerable=0
while IFS= read -r pkg_json; do
version=$(node -e "try{console.log(require('$pkg_json').version)}catch(e){console.log('error')}" 2>/dev/null)
if [ "$version" = "error" ] || [ -z "$version" ]; then
continue
fi
found=1
# Parse major.minor.patch
IFS='.' read -r major minor patch <<< "$version"
# Vulnerable: 7.0.0-7.29.0 or 8.0.0-8.10.1
if [ "$major" -eq 7 ]; then
if [ "$minor" -lt 29 ] || ([ "$minor" -eq 29 ] && [ "$patch" -lt 1 ]); then
echo "VULNERABLE — undici $version found at $pkg_json (fix: 7.29.1)"
vulnerable=1
else
echo "PATCHED — undici $version at $pkg_json"
fi
elif [ "$major" -eq 8 ]; then
if [ "$minor" -lt 10 ] || ([ "$minor" -eq 10 ] && [ "$patch" -lt 2 ]); then
echo "VULNERABLE — undici $version found at $pkg_json (fix: 8.10.2)"
vulnerable=1
else
echo "PATCHED — undici $version at $pkg_json"
fi
else
echo "PATCHED — undici $version at $pkg_json (outside affected range)"
fi
done < <(find "$PROJECT_DIR" -path '*/undici/package.json' -not -path '*/node_modules/.cache/*' 2>/dev/null)
if [ "$found" -eq 0 ]; then
echo "UNKNOWN — no undici installations found in $PROJECT_DIR"
exit 2
fi
if [ "$vulnerable" -eq 1 ]; then
exit 1
else
exit 0
fiIf you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.