Aug 4, 2026·7 min read·1 visit
Undici's retry interceptor failed to validate the Content-Length header against actual bytes received when retrying broken HTTP 206 Partial Content responses, creating desynchronization risks in downstream proxies.
A medium-severity vulnerability in Undici's retry interceptor causes body-length mismatches with the Content-Length header during HTTP 206 response resumption. Forwarding these inconsistent headers downstream leads to HTTP response desynchronization, connection hangs, or potential protocol smuggling.
The vulnerability exists within the HTTP client library undici for Node.js, specifically in its retry interceptor module (interceptors.retry()). Undici is widely deployed as a core HTTP client implementation across modern Node.js environments. The affected retry mechanism automates the resumption of failed or interrupted HTTP transfers, which includes reconstructing fragmented payloads using Range requests.
Under normal execution, the library abstracts retry logic away from the main application layer. However, when processing HTTP 206 Partial Content responses from an untrusted or faulty upstream server, the retry handler fails to verify that the reconstructed body size matches the original HTTP framing headers. This behavior creates a significant attack surface for applications operating in reverse proxy, API gateway, or middlebox configurations.
The underlying security flaw is classified under CWE-444: Inconsistent Interpretation of HTTP Requests. If an application forwards headers and payloads verbatim to downstream clients, the discrepancy between the declared Content-Length and the actual payload size can disrupt protocol boundaries in the downstream channel. This disruption leads to denial of service through connection hangs or protocol smuggling in environments utilizing HTTP persistent connections.
The root cause of CVE-2026-16728 resides in lib/handler/retry-handler.js. The retry handler is designed to manage connection failures transparently. When a socket connection terminates abruptly during a partial content transfer, the handler catches the error, determines the number of bytes successfully received, and issues a subsequent HTTP Range request to retrieve the remaining segment.
In the vulnerable implementation, the retry handler does not reconcile the metadata received in the initial HTTP response with the total volume of bytes eventually gathered across the sequence of range requests. If the upstream server provides an initial response with a mismatched framing header—such as a Content-Length of 300 but a Content-Range specifying 0-99/300—the interceptor processes only the partial range size (100 bytes) but leaves the original Content-Length header intact.
Once the connection closes early, the retry handler performs a subsequent request to pull the remaining byte offset. Upon assembling these segments, the final payload delivered to the client equals the total range size (100 bytes). Because the interceptor does not rewrite or validate the initial Content-Length: 300 header, the consuming Node.js application receives an HTTP response object where the body length is physically shorter than the value advertised in the headers.
To address the vulnerability, the maintainers introduced strict mathematical verification between the declared Content-Length and the expected range span. The core remediation involves the introduction of the validatePartialResponseContentLength utility in the retry handler, ensuring that any mismatch triggers an immediate error rather than proceeding with an incorrect payload assembly.
// Patched logic in lib/handler/retry-handler.js
function validatePartialResponseContentLength (headers, range, statusCode, retryCount) {
const contentLength = headers['content-length']
if (contentLength == null) {
return
}
// Ensure the parsed range boundaries are valid numbers
if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) {
return
}
const length = Number(contentLength)
const expectedLength = range.end - range.start + 1
// Validate physical length matches the mathematical boundaries of the range
if (!Number.isFinite(length) || length !== expectedLength) {
throw new RequestRetryError('Content-Length mismatch', statusCode, {
headers,
data: { count: retryCount }
})
}
}This validator is executed before any attempt to resume or retry the connection. If a mismatch is detected, a RequestRetryError is raised with the message Content-Length mismatch, immediately halting the transaction. This preventatively blocks the client from delivering corrupted frames to downstream callers.
The fix is robust against normal range responses but relies on the presence of the Content-Length header. If the upstream server uses chunked transfer encoding (Transfer-Encoding: chunked) and omits Content-Length, the validator exits early. In such cases, security depends on the downstream proxy correctly maintaining chunked boundaries rather than attempting to calculate a content length from unvalidated caches.
An attacker must control or compromise an upstream server to exploit this vulnerability. The target application must also use Undici with the retry interceptor enabled and forward upstream headers directly to downstream clients. The following interaction diagram illustrates the exploitation sequence:
First, the proxy issues a range request to the malicious upstream server. The upstream returns a response claiming a Content-Length of 300 but limits the Content-Range bounds to 0-99. After writing 99 bytes, the upstream server abruptly terminates the TCP socket.
The retry interceptor transparently resumes the connection by requesting the missing byte (bytes=99-99). The upstream provides the final byte, allowing Undici to compile a complete 100-byte response payload. Because the proxy application forwards the headers unmodified, it writes Content-Length: 300 to the downstream TCP socket but terminates the transmission after sending only 100 bytes. The downstream client remains in a reading state, hanging indefinitely while waiting for the remaining 200 bytes of data.
The primary impact of CVE-2026-16728 is downstream response desynchronization and denial of service. When a reverse proxy forwards an invalid Content-Length header, downstream HTTP parsers fail to identify the true boundary of the response body. If the downstream channel utilizes connection pooling or HTTP pipelining, the next request sent over that persistent connection may be parsed as part of the previous response's body.
This discrepancy can lead to cache poisoning or request smuggling if intermediate proxies process subsequent requests out of alignment. Even in simple non-pipelined configurations, the vulnerability causes downstream client connections to hang until a socket timeout occurs, degrading service availability.
The CVSS score is established at 4.8 (Medium), reflecting a high attack complexity because exploitation requires a multi-step sequence involving a malicious upstream server, specific configuration parameters (the retry interceptor), and an application that forwards headers without sanitization. The vulnerability does not directly expose sensitive data or allow remote code execution, but it exposes downstream infrastructure to synchronization-based exploits.
The definitive remediation for this vulnerability is to upgrade the undici library to a patched version. Maintainers have backported the fix to all active major releases. Security administrators should audit package locks and verify that Undici is updated according to the corresponding version track:
If using Undici v6.x, update to version 6.28.0 or higher. If using Undici v7.x, update to version 7.29.0 or higher. If using Undici v8.x, update to version 8.9.0 or higher.
If an immediate library upgrade is not possible, developers must implement defensive headers handling within the proxy application. Before emitting any response downstream, the application must strip the incoming Content-Length header or recalculate it dynamically using the actual length of the resolved buffer. Alternatively, forcing the proxy response to utilize Transfer-Encoding: chunked will bypass the downstream reliance on static content length fields and neutralize the framing mismatch.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
undici Node.js / OpenJS Foundation | < 6.28.0 | 6.28.0 |
undici Node.js / OpenJS Foundation | >= 7.0.0, < 7.29.0 | 7.29.0 |
undici Node.js / OpenJS Foundation | >= 8.0.0, < 8.9.0 | 8.9.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-444 |
| Attack Vector | Network |
| CVSS v3.1 Score | 4.8 |
| EPSS Score | 0.00164 |
| Impact | HTTP Response Desynchronization, Client Connection Hangs, Protocol Smuggling |
| Exploit Status | poc |
| Kev Status | Not Listed |
The platform does not sanitize or verify the consistency of length-related headers during retry operations, leading to mismatched HTTP framing parsing downstream.
CVE-2026-69252 represents a missing authorization check (CWE-862) in the files API route (`/api/v1/files`) of Flowise, a drag-and-drop user interface for building LLM flows. Prior to version 3.1.3, an authenticated API key or user could list, access, and delete files across arbitrary workspaces inside an organization, completely bypassing workspace logical boundaries.
A comprehensive technical analysis of CVE-2026-45584, a high-severity heap-based buffer overflow in Microsoft Defender's QEX parsing logic. The vulnerability resides within mpengine.dll and allows unauthenticated remote code execution or denial of service when processing crafted archives designed to trigger threat remediation and QEX history logging.
CVE-2026-16729 (GHSA-v3r7-h72x-cjcm) is a medium-severity cookie attribute injection vulnerability in Undici's web-compliant cookie utility module. Due to insufficient validation of domain parameters and raw attributes in the unparsed options array, arbitrary attributes like SameSite, HttpOnly, and Secure can be injected. This allows attackers to bypass CSRF protections, strip security flags, or override intended cookie behaviors when applications pass user-controlled values to these properties.
An interpretation conflict (CWE-436) in the cache interceptor of the undici HTTP client for Node.js causes whitespace-padded Cache-Control directives to be parsed incorrectly, leading to shared cache pollution and the unauthorized disclosure of sensitive, private, or authenticated user information (CWE-524).
CVE-2026-15157 details an improper neutralization of CRLF sequences ('CRLF Injection') within undici, a widely used Node.js HTTP/1.1 client. The vulnerability is triggered when processing request bodies that exhibit a duck-typed blob-like interface. When an application accepts untrusted data and assigns it to the .type property of such an object without setting an explicit Content-Type on the request, undici appends the value directly to the outgoing headers array without validating it against control characters. This allows remote attackers to inject carriage return and line feed sequences, culminating in arbitrary header injection, HTTP response splitting, or HTTP request smuggling.
A trust-boundary bypass and Server-Side Request Forgery (SSRF) vulnerability exists in the ip-address library versions 10.1.1 through 10.2.0 due to structural input misclassification. The library fails to resolve and normalize transition IP notations, such as IPv4-mapped IPv6 (::ffff:0:0/96) and NAT64 (64:ff9b::/96) addresses, to their embedded IPv4 representations prior to evaluation. Consequently, standard security validation checks (e.g., isLoopback, isLinkLocal, isULA) return false for these addresses. This allows remote attackers to bypass application-level IP address filters, gaining unauthorized access to internal resources, cloud metadata interfaces, and local services on dual-stack hosts or environments utilizing NAT64 gateways.