Aug 4, 2026·6 min read·50 visits
A vulnerability in undici allows attackers to inject CRLF sequences via duck-typed blob bodies, leading to HTTP Request Smuggling and Header Injection.
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.
The undici HTTP client library serves as a cornerstone for modern Node.js networking, delivering a high-performance HTTP/1.1 implementation. Applications routinely rely on undici to manage outward-bound communication, utilizing its dispatch pipelines to transmit various request payloads. The attack surface of concern involves outgoing requests that process non-standard or 'duck-typed' blob-like bodies.
Under specific circumstances, undici automates the generation of request headers to simplify operations for developers. If an outgoing request does not contain an explicit 'Content-Type' header, the dispatcher inspects the request body object. If this object mimics the native Blob interface, undici extracts its .type property and injects it directly into the outbound headers stream.
This automatic populating of headers introduces a serious vulnerability when the input is untrusted. Because the dispatcher did not subject this auto-extracted header to validation checks, it became a direct sink for Carriage Return and Line Feed (CRLF) characters. This class of flaw is classified under CWE-93, indicating an Improper Neutralization of CRLF Sequences.
The root cause of CVE-2026-15157 resides in the HTTP/1.1 dispatcher implementation located inside lib/dispatcher/client-h1.js. Specifically, the vulnerability manifests when processing the request payload within the writeH1 function. The dispatcher relies on the helper utility util.isBlobLike(body) to determine whether the incoming body possesses a Blob-like contract.
If the application developer has not defined a 'Content-Type' header, and the body object exhibits a truthy .type property, the vulnerable codebase executes the following instruction: headers.push('content-type', body.type). This step completely bypasses the header validation mechanism that governs other standard headers.
Normally, outgoing headers are validated to ensure they do not contain control characters or carriage returns. By pushing the raw body.type value directly into the serialization array, undici creates an unvalidated pathway. When the application writes this array to the underlying TCP socket, the raw CRLF sequences are interpreted by the receiving end as delimiters, causing the stream to segment prematurely.
A comparison of the vulnerable and patched versions reveals the exact injection point and the introduced validation guards. The fix was applied across the maintained branches in commits such as 33928bc24f742ea8422ed90d17f2e0cc83e4d09d.
@@ -1200,8 +1201,16 @@ function writeH1 (client, request) {
}
body = bodyStream.stream
contentLength = bodyStream.length
- } else if (util.isBlobLike(body) && request.contentType == null && body.type) {
- headers.push('content-type', body.type)
+ } else if (util.isBlobLike(body) && request.contentType == null) {
+ const contentType = body.type
+ if (contentType) {
+ const contentTypeValue = `${contentType}`
+ if (!util.isValidHeaderValue(contentTypeValue)) {
+ util.errorRequest(client, request, new InvalidArgumentError('invalid content-type header'))
+ return false
+ }
+ headers.push('content-type', contentTypeValue)
+ }
}The patch addresses the vulnerability with two primary additions. First, it extracts the contentType property and forces string coercion using template literals: const contentTypeValue = \${contentType}``. This coercion is a defense against Time-of-Check to Time-of-Use (TOCTOU) exploits, where a JavaScript Proxy could return a safe value during validation and a malicious string during serialization.
Second, the coerced string is analyzed using util.isValidHeaderValue(contentTypeValue). This function checks the string against defined specifications, ensuring that no control characters, including \r and \n, are present. If validation fails, undici immediately terminates the request and raises an InvalidArgumentError instead of writing corrupt sequences to the network socket.
Exploiting CVE-2026-15157 requires a specific alignment of application conditions. An attacker must find an application endpoint that accepts input and uses it to construct a custom object resembling a Blob. Furthermore, this object must be passed as a request body to undici, without the developer overriding the Content-Type header.
When these conditions are met, the attacker supplies a payload containing CRLF sequences. For instance, the attacker provides a string such as application/json\r\nInjected-Header: value. When undici serializes the headers, the downstream receiving server processes the raw bytes.
The receiving proxy identifies the first CRLF sequence as the end of the Content-Type header. It then reads the subsequent characters (Injected-Header: value) as an entirely separate header block. Under advanced conditions, the attacker can insert multiple CRLF sequences followed by a full HTTP request body, achieving HTTP Request Smuggling.
The primary risk associated with this CRLF injection is the compromise of message integrity across the delivery path. Because reverse proxies and load balancers rely heavily on explicit header boundaries to route traffic, injecting arbitrary headers allows attackers to manipulate proxy logic.
This manipulation can result in Web Cache Poisoning, where an attacker injects headers that force cache engines to store malicious responses under benign keys. Additionally, attackers can bypass security controls or web application firewalls (WAFs) by smuggling request payloads that are hidden from inspection engines.
This vulnerability has been assigned CVSS v3.1 base score of 4.2 (Medium), with a vector of CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N. The exploitability is limited by the requirement that applications must use custom, duck-typed blob shapes constructed from user input, as native runtime Blobs naturally sanitize the type property during instantiation.
Remediation requires updating undici to the corrected releases. Organizations should update dependencies to 6.28.0, 7.29.0, or 8.9.0 depending on their active release line. These versions correctly validate the headers during dispatch.
If immediate patching is unfeasible, developers must employ defensive code changes. The most direct workaround is to explicitly define the Content-Type header in the request options passed to undici. This step bypasses the vulnerable automatic header assignment logic entirely.
Additionally, applications that wrap or construct custom file-like objects from user parameters should perform strict verification. Sanitizing metadata properties to strip any carriage return and line feed characters prior to object property assignments provides defense-in-depth protection.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
undici Node.js | < 6.28.0 | 6.28.0 |
undici Node.js | >= 7.0.0 < 7.29.0 | 7.29.0 |
undici Node.js | >= 8.0.0 < 8.9.0 | 8.9.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-93 |
| Attack Vector | Network |
| CVSS v3.1 | 4.2 (Medium) |
| EPSS Score | 0.00142 |
| Impact | Low Confidentiality, Low Integrity |
| Exploit Status | PoC Available |
| KEV Status | Not Listed |
The product receives input from an upstream component but does not neutralize or incorrectly neutralizes carriage return (CR) and line feed (LF) characters before writing to an output stream interpreted as a protocol structure.
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.
CVE-2026-107717 represents a critical prompt boundary bypass and chat role injection vulnerability in the Banks Python package (versions prior to 2.5.0). The library parses generated template outputs line-by-line, attempting to validate each segment as a JSON-serialized ChatMessage object without validating the source boundaries of the text. If an application integrates user input directly into a prompt template, a remote, unauthenticated attacker can supply multi-line inputs with structured JSON payloads. This input is then parsed as high-privilege system instructions or tool execution responses, completely hijacking downstream Large Language Model behavior.
Improper pathname limitation and link resolution (CWE-22 and CWE-59) in the banks library prior to version 2.5.1 allow local attackers to read or write arbitrary files via crafted symbolic links in the prompt directory registry.