← Back to Feed CACHED · 2026-09-04 17:23:14 · CACHE_KEY CVE-2026-18540
CVE-2026-18540 · CWE-444 · Disclosed 2026-09-04

undici vulnerable to downstream response splitting via retry interceptor

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

Like leaving a gap between two train cars — only passengers walking between them at the exact wrong moment fall through

CVE-2026-18540 is a response-splitting flaw in undici's interceptors.retry() code path. When the retry interceptor resumes a partial HTTP response (e.g., after a socket close), it appends the resumed bytes to the already-delivered body without updating the original Content-Length header. An attacker who controls (or compromises) the upstream origin can craft a 404 Not Found with Content-Length: 2, send one byte, close the socket, and let the retry logic resume via a Range request — injecting additional bytes that spill past the declared boundary. If the calling application is a forwarding proxy or gateway that relays headers verbatim, the downstream HTTP parser sees extra bytes as the start of a new response, enabling classic HTTP response smuggling. Affected versions are undici < 6.28.1, 7.0.0–7.29.0, and 8.0.0–8.10.1. Patched in 6.28.1, 7.29.1, and 8.10.2.

The vendor rated this LOW / 3.7 and that score is honest. Three conditions must hold simultaneously: (1) the retry interceptor is explicitly enabled, (2) the attacker controls or influences the upstream origin, and (3) the downstream application forwards Content-Length without recalculation. Most undici consumers are outbound HTTP clients in server-side apps that consume responses locally — they never relay raw headers downstream. The proxy/gateway pattern where this matters is a small fraction of the 175M-weekly-download install base, and the impact ceiling is integrity-only (no confidentiality, no RCE). The vendor's LOW is appropriate.

"Narrow proxy-only smuggling bug; vendor LOW score is fair given triple-condition chain"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Attacker controls upstream origin

The attacker must be able to serve crafted HTTP responses to the target undici client. This means the attacker either owns the upstream server, has compromised it, or sits in a MITM position. Without control of the origin's response framing, the attack cannot begin.
Conditions required:
  • Attacker controls or influences the upstream HTTP server responding to the undici client
Where this breaks in practice:
  • In most architectures the upstream origin is a trusted internal service or well-known third-party API — not attacker-controlled
  • MITM requires TLS interception or a compromised network path
STEP 02

Retry interceptor enabled and triggers resume

The target application must have explicitly configured interceptors.retry() on its undici client. The attacker sends a partial response (e.g., Content-Length: 2 but only 1 byte delivered), then closes the socket. The retry interceptor fires a Range-based resume request, appending additional bytes to the already-in-flight body without updating Content-Length.
Conditions required:
  • Application has interceptors.retry() enabled (not default behavior — must be explicitly configured)
  • Upstream response triggers a retry condition (socket close mid-body)
Where this breaks in practice:
  • Retry interceptor is opt-in; most undici users rely on default fetch/request without retry middleware
  • Retry logic may be configured with maxRetries: 0 or limited to idempotent methods only
Detection/coverage: Code audit or dependency scan for interceptors.retry() usage in application source
STEP 03

Downstream forwarding without Content-Length recalculation

The application must act as a proxy or gateway, forwarding the upstream response headers and body to a downstream client verbatim. The stale Content-Length causes the downstream HTTP parser to interpret trailing bytes as a new response, achieving response splitting/smuggling.
Conditions required:
  • Application forwards upstream response headers (including Content-Length) without stripping or recalculating them
  • Downstream connection is keep-alive (HTTP/1.1 pipelining or connection reuse)
Where this breaks in practice:
  • Most Node.js proxy frameworks (http-proxy, fastify-reply-from, Next.js SSR) recalculate Content-Length or use Transfer-Encoding: chunked
  • HTTP/2 downstream eliminates classical response splitting since framing is binary, not length-delimited
STEP 04

Response smuggling impact

With a desynchronized downstream connection, the attacker can inject a crafted response that the downstream client interprets as belonging to a different request. This enables cache poisoning, session fixation via injected Set-Cookie, or serving malicious content to a different user sharing the same downstream connection.
Conditions required:
  • Downstream client or intermediary (CDN, load balancer) reuses the poisoned connection for subsequent requests
Where this breaks in practice:
  • Modern CDNs and load balancers have their own response validation and framing checks
  • Impact is limited to integrity — no code execution, no direct credential theft
Detection/coverage: WAF rules detecting Content-Length / body mismatch anomalies; HTTP desync detection in reverse proxies
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone observed. No reports of active exploitation. Not listed in CISA KEV.
Proof of ConceptNo public PoC exploit. The advisory description from reporter samuel871211 outlines the theoretical attack path but no weaponized tooling exists.
EPSS ScoreNot yet scored (advisory published 2026-09-04, EPSS lag expected). Likely to land in the bottom 10th percentile given LOW severity and high attack complexity.
KEV StatusNot listed. No CISA KEV entry.
CVSS VectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N — Network-reachable but High complexity, no privileges needed, integrity-only impact. No confidentiality or availability impact.
Affected Versionsundici < 6.28.1, 7.0.0 – 7.29.0, 8.0.0 – 8.10.1
Fixed Versions6.28.1, 7.29.1, 8.10.2
Scanning / Exposureundici has ~175M weekly npm downloads. However, the vulnerable code path (retry interceptor in proxy mode) represents a small fraction of deployments. No Shodan/GreyNoise exposure surface — this is a library, not a listening service.
Disclosure Date2026-09-04 (GHSA-r53p-7pc4-xj5r published)
Reportersamuel871211 (reporter); mcollina (remediation developer); UlisesGascon (reviewer)
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to LOW (3.7/10)

The single most decisive factor is the triple-condition chain: exploitation requires attacker-controlled upstream, explicitly enabled retry interceptor, AND verbatim header forwarding — a combination that describes a vanishingly small subset of the 175M-weekly-download install base. The integrity-only impact ceiling (no RCE, no confidentiality breach) further confirms the vendor's LOW rating.

HIGH Vulnerability mechanics and affected versions
HIGH Vendor severity alignment
MEDIUM Exploit feasibility in real proxy deployments

Why this verdict

  • Triple prerequisite chain compresses reachable population. Three independent conditions — attacker-controlled upstream, retry interceptor enabled, verbatim header forwarding — must all hold. Each condition independently eliminates the majority of undici deployments.
  • Integrity-only impact with no escalation path. Even when the chain succeeds, the outcome is HTTP response desynchronization — cache poisoning or injected headers. There is no path to RCE, credential theft, or lateral movement from this flaw alone.
  • Role multiplier: low blast radius across deployment roles. undici is predominantly used as an outbound HTTP client in server-side Node.js apps. (a) *Low-value role*: CLI tools, dev servers, scripts — not affected (no downstream forwarding). (b) *Typical role*: API backends consuming upstream services — consume responses locally, never relay raw headers. (c) *High-value role*: Node.js-based reverse proxies or API gateways — this is where the chain could succeed, but these represent <5% of undici installs, and the blast radius is limited to downstream response corruption on that single proxy's connections (not domain/fleet/supply-chain scale). No high-value-role floor trigger applies.
  • No exploitation evidence or tooling. No PoC, no KEV listing, no observed campaigns. The advisory is 1 day old with zero community weaponization.

Why not higher?

Upgrading to MEDIUM or above would require either a broader reachable population or a more severe impact. The attack demands the attacker already control the upstream origin — if they have that, they can serve arbitrary malicious content directly, making this smuggling vector a marginal incremental risk. The integrity-only impact with no confidentiality or availability component, combined with the opt-in retry interceptor requirement, keeps this firmly in LOW territory.

Why not lower?

IGNORE would understate the risk for the small population of Node.js-based forwarding proxies that do use retry interceptors. HTTP response smuggling is a well-understood attack class (CWE-444) with real consequences when conditions align — cache poisoning can affect many downstream users. The flaw is real, patched, and deserves tracking even if urgency is minimal.

05 · Compensating Control

What to do — in priority order.

  1. Disable the retry interceptor on proxy/gateway workloads — Set maxRetries: 0 or remove interceptors.retry() from undici client configuration in any application that forwards responses downstream. This eliminates the vulnerable code path entirely. No mitigation SLA applies for LOW severity — go straight to remediation.
  2. Recalculate or strip Content-Length before forwarding — If your Node.js proxy forwards upstream responses, ensure you delete the Content-Length header and use Transfer-Encoding: chunked, or recalculate Content-Length from the actual body bytes. This breaks the smuggling vector regardless of undici version.
  3. Use HTTP/2 for downstream connections — HTTP/2's binary framing eliminates classical Content-Length-based response splitting. If your proxy serves downstream clients over HTTP/2 (h2 or h2c), the smuggling payload cannot desynchronize the connection.
What doesn't work
  • WAF signature for request smuggling — this is *response* splitting, not request smuggling. Most WAF CL/TE desync rules inspect inbound requests, not outbound responses from your own proxy.
  • Upgrading Node.js without upgrading undici — Node.js bundles undici but application-level npm install undici takes precedence. You must upgrade the explicit undici dependency in your package.json, not just the Node.js runtime.
06 · Verification

Crowdsourced verification payload.

Run this on any host where the target Node.js application is deployed, or in your CI pipeline. Requires access to the application's node_modules directory. Example: bash check_cve_2026_18540.sh /app (pass the project root as the first argument). No elevated privileges needed.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_18540.sh — Detect undici versions vulnerable to CVE-2026-18540
# Usage: bash check_cve_2026_18540.sh /path/to/project

set -euo pipefail

PROJECT_DIR="${1:-.}"
PKG="$PROJECT_DIR/node_modules/undici/package.json"

if [ ! -f "$PKG" ]; then
  echo "UNKNOWN — undici not found in $PROJECT_DIR/node_modules"
  exit 2
fi

VERSION=$(grep '"version"' "$PKG" | head -1 | sed 's/.*"version": *"\([^"]*\)".*/\1/')
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)

echo "Detected undici version: $VERSION"

vulnerable=0

# Branch 6.x: vulnerable if < 6.28.1
if [ "$MAJOR" -lt 6 ]; then
  vulnerable=1
elif [ "$MAJOR" -eq 6 ]; then
  if [ "$MINOR" -lt 28 ]; then
    vulnerable=1
  elif [ "$MINOR" -eq 28 ] && [ "$PATCH" -lt 1 ]; then
    vulnerable=1
  fi
# Branch 7.x: vulnerable if 7.0.0 – 7.29.0
elif [ "$MAJOR" -eq 7 ]; then
  if [ "$MINOR" -lt 29 ]; then
    vulnerable=1
  elif [ "$MINOR" -eq 29 ] && [ "$PATCH" -lt 1 ]; then
    vulnerable=1
  fi
# Branch 8.x: vulnerable if 8.0.0 – 8.10.1
elif [ "$MAJOR" -eq 8 ]; then
  if [ "$MINOR" -lt 10 ]; then
    vulnerable=1
  elif [ "$MINOR" -eq 10 ] && [ "$PATCH" -lt 2 ]; then
    vulnerable=1
  fi
fi

if [ "$vulnerable" -eq 1 ]; then
  echo "VULNERABLE — undici $VERSION is affected by CVE-2026-18540"
  # Check if retry interceptor is used in the project
  if grep -rq 'interceptors\.retry\|interceptors\.retry(' "$PROJECT_DIR/src" "$PROJECT_DIR/lib" "$PROJECT_DIR/app" 2>/dev/null; then
    echo "WARNING — retry interceptor usage detected in source code"
  else
    echo "NOTE — no retry interceptor usage found in common source directories (reduced risk)"
  fi
  exit 1
else
  echo "PATCHED — undici $VERSION is not affected"
  exit 0
fi
07 · Bottom Line

If you remember one thing.

TL;DR
This is a LOW-severity library bug with a narrow blast radius. There is no noisgate mitigation SLA for LOW — treat it as backlog hygiene. Roll the undici upgrade (npm install [email protected] or the appropriate branch) into your next scheduled dependency update cycle. If you operate a Node.js-based reverse proxy or API gateway that uses interceptors.retry(), bump priority slightly and confirm your forwarding layer recalculates Content-Length. For the vast majority of teams consuming undici as an outbound HTTP client, this CVE requires no emergency action — update when convenient within your normal noisgate remediation SLA cadence and move on.

Sources

  1. GitHub Security Advisory GHSA-r53p-7pc4-xj5r
  2. undici Security Advisories Index
  3. Related Advisory: CVE-2026-16728 Response Desynchronization
  4. undici npm Package
  5. CWE-444: Inconsistent Interpretation of HTTP Requests
  6. undici Releases (GitHub)
  7. SentinelOne Vulnerability Database — undici
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.