Aug 4, 2026·7 min read·90 visits
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-107718 is a medium-severity Open Redirect vulnerability in the core HTTP server package of the AdonisJS Node.js framework. Prior to versions 8.2.3 and 9.3.0, the framework built route paths by directly interpolating dynamic parameters and wildcard segments without URI encoding. If an application routes attacker-controlled input directly to a dynamic first path segment and uses the generated route URL as a redirect destination, a leading slash can produce a scheme-relative external URL. Modern web browsers process scheme-relative URLs by redirecting the client to the specified external domain, exposing users to credential harvesting, social engineering, and session hijacking. This vulnerability affects all applications running unpatched configurations where input validation is not explicitly implemented before generating paths.
CVE-2026-107725 is a critical security bypass in Hazelcast where missing authorization checks in the MapPermission class permit unprivileged clients to issue queries containing aggregators or projections. This architectural oversight allows attackers to run arbitrary code on the cluster servers under the privileges of the active Hazelcast process.
A stored Cross-Site Scripting (XSS) vulnerability was identified in Indico, an open-source event management system developed at CERN, prior to version 3.3.13. The vulnerability stems from weak URL validation in custom link fields and lack of HTML sanitization during Marshmallow serialization of event notes. This allows authenticated attackers with event modification privileges to inject malicious payloads that execute in the browser of users viewing the event pages or collaborating on notes.
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.
An authorization bypass vulnerability exists in the legacy session export API of Indico, an open-source event management system developed at CERN. Due to a missing object-level access check, authenticated users can bypass configuration-level restrictions to extract private session metadata (including session titles, descriptions, and list of conveners) from events that they are otherwise authorized to view.
An incomplete Server-Side Request Forgery (SSRF) validation check in Indico prior to version 3.3.13 allows authenticated event organizers to bypass outbound network restrictions. By utilizing backslash characters within crafted URLs, attackers can exploit a parser differential between the application's validator and the downstream HTTP client library to access internal network resources.