← Back to Feed CACHED · 2026-07-29 22:37:25 · CACHE_KEY CVE-2026-13697
CVE-2026-13697 · CWE-200 · Disclosed 2026-07-29

undici's cache interceptor mishandles malformed Cache-Control private directives

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Like leaving a shared locker open because someone wrote the combination with extra spaces

CVE-2026-13697 affects undici's cache interceptor, introduced in v7. When an upstream origin server sends a Cache-Control header with whitespace-padded qualified field names — e.g. private=" authorization" or no-cache="\tauthorization" — the parser preserves the surrounding whitespace. The subsequent string comparison against the literal authorization token fails, so undici incorrectly classifies the response as cacheable. In shared-cache mode, a response containing one user's authenticated data can then be served from cache to a different caller, including an unauthenticated one, when both requests resolve to the same cache key. Affected versions are 7.0.0 through 7.27.x and 8.0.0 through 8.4.x; fixes land in 7.28.0 and 8.5.0.

The vendor rates this HIGH at 7.4, but that overstates the real-world risk by a full severity tier. The cache interceptor is not enabled by default — developers must explicitly call interceptors.cache() to activate it. Even among those who do, the vulnerability further requires the origin server to emit non-standard whitespace-padded Cache-Control directives, which is rare in production. The vendor's CVSS vector also includes A:H (Availability: High), but the documented mechanism is a cache-logic parsing error that produces information disclosure, not service disruption. The earlier GHSA-pr7r-676h-xcf6 advisory for the closely related CVE-2026-9678 scored the same class of bug at 5.9 MODERATE with A:N, which better reflects the actual impact.

"Vendor says HIGH but the cache interceptor is opt-in and the trigger requires malformed origin headers. Real risk is MEDIUM."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify target using undici cache interceptor in shared mode

The attacker identifies a Node.js backend service (e.g., an API gateway or BFF layer) that uses undici as its HTTP client with interceptors.cache() explicitly enabled. Shared mode is the default *when the cache is enabled*, but the cache itself is opt-in. The attacker must target a service where authenticated requests are proxied through undici with caching active.
Conditions required:
  • Target service runs undici >=7.0.0 and <7.28.0, or >=8.0.0 and <8.5.0
  • Cache interceptor is explicitly enabled via interceptors.cache()
  • Cache operates in shared mode (default when enabled)
Where this breaks in practice:
  • The cache interceptor is opt-in and relatively new (introduced in v7) — most undici consumers never enable it
  • No external fingerprint reveals whether the cache interceptor is active; attacker needs inside knowledge or code access
STEP 02

Origin server emits malformed Cache-Control

The upstream origin server responds with a Cache-Control header containing whitespace-padded qualified private or no-cache field names, such as private=" authorization" or no-cache="\tauthorization". This is non-standard formatting that legitimate HTTP servers almost never produce. The attacker does not control this — it must already be a property of the origin server's response headers.
Conditions required:
  • Origin server sends non-standard whitespace in Cache-Control qualified field names
  • The response includes sensitive per-user data gated by the Authorization header
Where this breaks in practice:
  • Standard HTTP libraries and frameworks produce canonical Cache-Control values without whitespace padding
  • An attacker cannot inject or modify the origin's response headers unless they have a separate header-injection vulnerability
STEP 03

Whitespace bypass causes incorrect caching

Undici's cache interceptor parses the Cache-Control header but preserves the leading/trailing whitespace on field names. When it later checks whether authorization is in the private or no-cache list, the string comparison fails because " authorization" does not equal "authorization". The response is therefore classified as cacheable and stored in the shared cache.
Conditions required:
  • The whitespace-padded field name must exactly target a field undici compares (e.g., authorization)
Where this breaks in practice:
  • If the origin uses standard formatting, the comparison succeeds and the response is correctly excluded from the cache
Detection/coverage: Code review of Cache-Control header values in upstream responses; custom middleware logging non-canonical directive formatting
STEP 04

Second user receives cached authenticated response

A subsequent request from a different user (or an unauthenticated caller) to the same endpoint resolves to the same cache key. The shared cache serves the first user's authenticated response, leaking their data. The attacker sees PII, tokens, or other sensitive information that should have been private to the original user.
Conditions required:
  • Both requests resolve to the same cache key (same URL, matching Vary headers)
  • The attacker can reach the same endpoint within the cache TTL
Where this breaks in practice:
  • If the origin includes Vary: Authorization, cache keys differ per-user and the leak does not occur
  • Short cache TTLs reduce the exploitation window
Detection/coverage: Application-level logging of cache hits on authenticated endpoints; anomaly detection on response content served to different users
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No campaigns, threat actor reports, or honeypot hits reference this CVE as of 2026-07-30.
Proof of conceptNone public. No PoC repositories, blog posts, or researcher demos have been published. The exploit requires a non-standard origin header, making generic PoC tooling unlikely.
EPSS scoreNot yet scored (CVE disclosed 2026-07-29). Related CVE-2026-9678 in the same cache interceptor class had an EPSS of approximately 0.64%, placing it well below the 90th percentile.
KEV statusNot listed. CISA KEV catalog does not include this CVE.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H — vendor assigns 7.4 HIGH. The AC:H correctly reflects the non-trivial preconditions. The A:H component is debatable; the documented mechanism is information disclosure, not denial of service. The earlier GHSA for CVE-2026-9678 used A:N and scored 5.9.
Affected versionsundici 7.0.0 – 7.27.x and 8.0.0 – 8.4.x. Versions prior to 7.0.0 (including the entire 6.x and 5.x lines) are not affected because the cache interceptor did not exist.
Fixed versions7.28.0 (v7 branch) and 8.5.0 (v8 branch). Node.js core bundles undici; check Node.js release notes for bundled version updates.
Exposure / install baseundici has ~125M+ weekly npm downloads (npm trends), but the cache interceptor is opt-in and relatively new (v7+). The *reachable* population is a small fraction of total installs. No Shodan/Censys/GreyNoise exposure data is relevant — this is a client-side library, not a listening service.
Disclosure date2026-07-29 via GitHub Security Advisory GHSA-pr7r-676h-xcf6.
CreditReported via the Node.js / OpenJS Foundation CNA. Specific researcher not publicly credited at time of writing.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.0/10)

The single most decisive factor driving the downgrade is that undici's cache interceptor is opt-in — not enabled by default — which narrows the vulnerable population to a small fraction of undici's 125M+ weekly download base. Combined with the requirement for non-standard whitespace-padded Cache-Control directives from the origin server, the exploitable attack surface shrinks to an edge case rather than a broadly reachable condition.

HIGH Vulnerability mechanism and affected version range
MEDIUM Size of the population actually using cache interceptor in shared mode
LOW Availability impact (vendor A:H appears unsubstantiated by documented mechanism)

Why this verdict

  • Opt-in feature narrows population: The cache interceptor must be explicitly enabled via interceptors.cache() — it is not active by default. This alone eliminates the vast majority of undici's 125M+ weekly download base from the vulnerable population. Downward pressure: significant.
  • Non-standard origin behavior required (AC:H): Exploitation requires the upstream origin server to independently send malformed whitespace-padded Cache-Control field names like private=" authorization". This is non-standard and rare in production environments. The attacker cannot cause this condition without a separate header-injection bug. Downward pressure: significant.
  • No exploitation evidence: No PoC, no KEV listing, no in-the-wild campaigns observed. EPSS for the related CVE-2026-9678 is approximately 0.64%. Downward pressure: moderate.
  • Availability impact overrated: The vendor vector includes A:H, but the documented vulnerability mechanism — whitespace in Cache-Control parsing causing incorrect caching — produces *information disclosure*, not service disruption. The GHSA for the same class of bug used A:N (CVSS 5.9). Adjusting A:H to A:N alone would drop the score from 7.4 to 5.9. Downward pressure: moderate.
  • Role multiplier: undici is a client-side HTTP library embedded in Node.js backends. In an API gateway or BFF role, the chain could succeed and leak user-to-user data at the *application/tenant* scope — not fleet, domain, or supply-chain scope. undici is not canonically a high-value-role component (it is not a hypervisor, IdP, PAM, backup server, CA, or network edge device). The blast radius does not meet the floor threshold for HIGH because compromise is bounded to one application's user base, not infrastructure-wide takeover.

Why not higher?

No known exploitation in the wild, no PoC code, and no KEV listing. The attack requires two independent, unusual preconditions (opt-in cache explicitly enabled AND malformed origin headers) — making real-world exploitation unlikely without a targeted campaign against a known vulnerable service. The blast radius is application-tenant scoped, not infrastructure-wide.

Why not lower?

When the preconditions ARE met, the impact is genuine cross-user data leakage with no authentication required from the attacker (PR:N, AV:N). undici's massive install base means even a small opt-in percentage translates to thousands of potentially affected services. The confidentiality impact (C:H) is real and could expose PII, session tokens, or API keys cached from another user's response.

05 · Compensating Control

What to do — in priority order.

  1. Switch cache interceptor to private mode for authenticated routes — Change interceptors.cache({ type: 'private' }) or disable the cache entirely for routes that forward Authorization headers. This eliminates the cross-user leak vector regardless of origin header formatting. Apply within the noisgate MEDIUM remediation window (365 days), though sooner is better for services handling sensitive data.
  2. Add Vary: Authorization on origin servers — Configure upstream origins to include Vary: Authorization in responses. This forces cache keys to differ per Authorization header value, preventing cross-user cache hits even if the response is incorrectly classified as cacheable. This is a server-side change, not an undici change.
  3. Upgrade undici to >=7.28.0 or >=8.5.0 — The definitive fix. Run npm update undici or pin the patched version in package.json. For applications using Node.js core fetch, check whether your Node.js release bundles an updated undici. Target within the 365-day noisgate remediation SLA.
  4. Exclude authenticated requests from cache interceptor — If you cannot upgrade immediately, add application logic to bypass the cache interceptor for any request carrying an Authorization header. This prevents sensitive responses from entering the shared cache at all.
What doesn't work
  • WAF rules — The vulnerability is in client-side outbound HTTP caching logic inside the Node.js process, not in inbound request handling. A WAF sitting in front of the service cannot see or control how undici processes upstream Cache-Control headers.
  • Network segmentation / firewalls — This is an application-layer cache logic issue. Network controls do not affect how undici parses or stores cached HTTP responses.
  • Rate limiting — Throttling requests does not prevent a cached response from being served to the wrong user; a single well-timed request within the cache TTL is sufficient.
06 · Verification

Crowdsourced verification payload.

Run this script from the root directory of any Node.js project on the target host. It checks the installed undici version against the affected ranges. Requires node on PATH; no elevated privileges needed. Example: bash check_cve_2026_13697.sh /opt/myapp

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# noisgate CVE-2026-13697 checker
# Detects vulnerable undici versions (cache interceptor whitespace bypass)
# Run from a Node.js project root. No elevated privileges needed.
# Usage: bash check_cve_2026_13697.sh [/path/to/project]
set -euo pipefail
DIR=${1:-.}
if [ ! -d "$DIR" ]; then
  echo "UNKNOWN - directory not found"; exit 2
fi
cd "$DIR"
VER=
if [ -f node_modules/undici/package.json ]; then
  VER=$(node -p 'require("./node_modules/undici/package.json").version' 2>/dev/null || true)
fi
if [ -z "$VER" ] && command -v npm &>/dev/null && [ -f package.json ]; then
  VER=$(npm ls undici --depth=0 2>/dev/null | grep -oE 'undici@[0-9]+\.[0-9]+\.[0-9]+' | head -1 | cut -d@ -f2 || true)
fi
if [ -z "$VER" ]; then
  echo "UNKNOWN - undici not detected"; exit 2
fi
IFS=. read -r MAJ MIN PAT <<< "$VER"
if [ "$MAJ" -lt 7 ]; then
  echo "PATCHED - undici $VER predates cache interceptor (not affected)"; exit 0
elif [ "$MAJ" -eq 7 ] && [ "$MIN" -lt 28 ]; then
  echo "VULNERABLE - undici $VER (fix: >=7.28.0)"; exit 1
elif [ "$MAJ" -eq 8 ] && [ "$MIN" -lt 5 ]; then
  echo "VULNERABLE - undici $VER (fix: >=8.5.0)"; exit 1
else
  echo "PATCHED - undici $VER"; exit 0
fi
07 · Bottom Line

If you remember one thing.

TL;DR
This is an opt-in feature vulnerability in undici's cache interceptor, disclosed 2026-07-29 as CVE-2026-13697. noisgate reassesses this as MEDIUM (5.0), down from the vendor's HIGH (7.4). If your Node.js services use interceptors.cache() in shared mode with Authorization header forwarding, audit those services first — search your codebase for interceptors.cache calls and run the verification script across your Node.js fleet. There is no noisgate mitigation SLA for MEDIUM — go straight to the 365-day noisgate remediation SLA by upgrading undici to >=7.28.0 or >=8.5.0 during your next maintenance cycle. If you do NOT use the cache interceptor (the default for undici), this CVE does not affect you and can be bundled into routine dependency updates. Prioritize services handling PII or financial data if you must triage within the MEDIUM tier.

Sources

  1. GitHub Security Advisory GHSA-pr7r-676h-xcf6
  2. SecurityOnline — Four undici Vulnerabilities (133M Weekly Downloads)
  3. NVD — CVE-2026-9678 (related cache interceptor CVE)
  4. undici releases on GitHub
  5. Platformatic — Bringing HTTP Caching to Node.js
  6. npm trends — undici download statistics
  7. OpenJS Foundation CNA — Security Advisories
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.