Sep 16, 2026·5 min read·1 visit
A lenient HTTP chunk decoder in the http4s Ember server allows TE.TE request and response smuggling attacks when combined with strict upstream reverse proxies.
An HTTP Request/Response Smuggling vulnerability (CVE-2026-69216) was identified in the Ember chunked transfer encoding decoder of the http4s Scala library. Due to parser leniency accepting sign prefixes, surrounding whitespace, and missing trailing CRLFs, attackers can bypass proxy security boundaries, poison shared caches, or hijack request queues.
CVE-2026-69216 defines a protocol parsing vulnerability within the Ember HTTP server and client components of http4s, a modular, functional Scala interface for HTTP services. The vulnerability lies within the chunked transfer encoding parsing engine, which handles data streams with the Transfer-Encoding: chunked header. This implementation is packaged within the http4s-ember-core library.\n\nThe issue stems from a structural divergence between how Ember handles chunked transport boundaries and how front-end proxies enforce the RFC 9112 specification. An unauthenticated remote attacker can exploit this discrepancy to construct HTTP Request Smuggling (specifically TE.TE request smuggling) or Response Smuggling attacks.\n\nWhen an intermediary reverse proxy is configured to route traffic to an http4s backend, the differences in parsing behavior allow an attacker to desynchronize the connection state. This desynchronization can be leveraged to execute unauthorized operations, poison web application caches, or capture sensitive user requests.
The RFC 9112 specification defines strict parsing requirements for chunked transfer coding. Specifically, Section 7.1 dictates that the chunk-size token must consist exclusively of one or more hexadecimal digits, without any signs or leading/trailing whitespace. Furthermore, each segment of chunked data must be immediately followed by a carriage return line feed (CRLF) sequence.\n\nThe vulnerable Ember implementation in ChunkedEncoding.scala failed to meet these specifications in three ways. First, the parser extracted the chunk size substring and applied the .trim operation to it, stripping all surrounding whitespace. Second, the trimmed string was passed to Java's java.lang.Long.parseLong(..., 16), which natively tolerates leading plus (+) or minus (-) symbols.\n\nThird, the decoder failed to strictly validate that a CRLF sequence directly followed the parsed chunk data. Instead, the implementation relied on a lenient leading-CRLF strip when commencing the parsing of the subsequent chunk header. This allowed missing or duplicated delimiters to go unnoticed by the backend while stricter proxies parsed them differently.
In the vulnerable version of ChunkedEncoding.scala, chunk headers were decoded using the readChunkedHeader function, which processed incoming byte vectors as shown below:\n\nscala\n// VULNERABLE CODE\nprivate def readChunkedHeader(hdr: ByteVector): Option[Long] =\n hdr.decodeUtf8.toOption.flatMap { s =>\n val parts = s.split(';') // Ignore extensions\n if (parts.isEmpty) None\n else\n try Some(java.lang.Long.parseLong(parts(0).trim, 16))\n catch { case NonFatal(_) => None }\n }\n\n\nThe patch implemented in commit d78612a5abd5a2547487598d3342be05573e16f0 addresses these weaknesses by enforcing explicit hex validations. It discards the unsafe .trim and Java's default sign parsing behavior, and instead checks every character against a strict hex predicate:\n\nscala\n// PATCHED CODE\nprivate def readChunkedHeader(hdr: ByteVector): Option[Long] =\n hdr.decodeUtf8.toOption.flatMap { s =>\n val size = s.takeWhile(_ != ';') // Ignore any chunk-ext\n if (size.nonEmpty && size.forall(CharPredicate.HexDigit))\n try Some(java.lang.Long.parseLong(size, 16))\n catch { case NonFatal(_) => None }\n else None\n }\n\n\nFurthermore, the patch introduces a requireCrlf check to enforce that the trailing CRLF delimiter is present immediately after the chunk data, preventing the parser from skipping missing delimiters:\n\nscala\n// ENFORCED TRAILING CRLF IN PATCH\ndef requireCrlf(buf: ByteVector): Pull[F, Byte, Unit] =\n if (buf.size < crlf.size)\n Pull.eval(read).flatMap {\n case None => Pull.raiseError[F](EmberException.ReachedEndOfStream())\n case Some(c) => requireCrlf(buf ++ c.toByteVector)\n }\n else if (buf.startsWith(crlf))\n go(Left(ByteVector.empty), buf.drop(crlf.size))\n else\n Pull.raiseError[F](\n EmberException.ChunkedEncodingError(\"Expected CRLF after chunk data\")\n )\n
Exploitation of CVE-2026-69216 requires an environment where an intermediate proxy and an http4s backend communicate over persistent TCP connections. The attacker crafts a request with a Transfer-Encoding: chunked header containing syntactically malformed chunk-size fields that the proxy passes through but the backend accepts.\n\nmermaid\ngraph LR\n A[\"Attacker Client\"] -->|\"Malformed request with +5 or trailing spaces\"| B[\"Reverse Proxy\"]\n B -->|\"Forwarded TCP Stream\"| C[\"http4s Backend (Lenient Parser)\"]\n C -->|\"Parses +5 as 5, leaving residual stream\"| D[\"Socket Buffer (Smuggled Request)\"]\n\n\nFor instance, an attacker might submit a chunk size of +5 or 5 . A strict front-end proxy might not modify this boundary but simply forward the stream, or it may interpret the boundary size differently if it does not parse signs. The http4s backend, using Long.parseLong(\"+5\", 16), treats it as a decimal value of 5, reads the chunk data, and then fails to validate the trailing CRLF, leaving subsequent request data buffered on the connection.\n\nWhen a subsequent user transmits a normal request over the same shared connection, the http4s server prepends the leftover buffered bytes to that user's incoming request. The server then executes the combined request under the authority of the victim, leading to request queue hijacking or credential extraction.
The impact of this vulnerability is classified as medium severity with a CVSS v3.1 base score of 5.4. The attack vector is Network (AV:N), the attack complexity is High (AC:H), and privileges required are None (PR:N). Scope is changed (S:C) because exploitation modifies the state of downstream shared caches and proxy connections.\n\nA successful attack allows the bypass of security controls deployed at the proxy layer, such as route restrictions or WAF rules. Because smuggled requests bypass proxy validation, restricted endpoints can be accessed directly.\n\nAdditionally, this vulnerability facilitates web cache poisoning. By smuggling a request that triggers a specific response, an attacker can manipulate caching proxies to cache malicious content for legitimate URLs, distributing arbitrary scripts to other application users.
The primary remediation strategy is to upgrade all http4s installations using the Ember component to secure versions. For the 0.23.x release line, the issue is resolved in 0.23.35. For the 1.0.0 milestone line, the issue is resolved in 1.0.0-M47.\n\nIf upgrading is not immediately feasible, operators should implement intermediate mitigations at the proxy or network level. Reverse proxies should be configured to re-encode or normalize chunked transfer encoding requests, which strips invalid trailing whitespace and signs prior to backend forwarding.\n\nAlternatively, migrating public-facing endpoints to HTTP/2 or HTTP/3 effectively neutralizes the issue. Because these modern protocols use binary framing to delimit length rather than character-based chunk separators, the parsing weaknesses present in the text-based chunked parser cannot be triggered.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
http4s-ember-core Typelevel | < 0.23.35 | 0.23.35 |
http4s-ember-core Typelevel | >= 1.0.0-M1, < 1.0.0-M47 | 1.0.0-M47 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-444 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.4 (Medium) |
| EPSS Score | Not yet calculated |
| Impact | Request/Response Smuggling, Cache Poisoning, Bypass of Proxy Controls |
| Exploit Status | None/PoC |
| KEV Status | Not Listed |
The application does not properly parse or validate HTTP request headers, boundaries, or transfer encodings in a manner consistent with RFC standards, leading to discrepancies when parsed by upstream devices.
A medium-severity cross-origin cookie leakage vulnerability exists in the CookieJar client middleware of the http4s library. Due to unanchored substring searches used to determine whether a cookie applies to an outbound request, sensitive cookies (such as session IDs and credentials) can be inadvertently sent to unauthorized domains or paths.
A critical resource exhaustion vulnerability exists in the http4s Ember HTTP/2 server and client implementations. By failing to limit the size or quantity of incoming HTTP/2 CONTINUATION frames, the engine allows unauthenticated remote attackers to exhaust JVM heap memory, causing a complete Denial of Service.
CVE-2026-69201 is a critical directory traversal vulnerability in the http4s Scala library. Affected versions of ResourceService and WebjarService allow attackers to escape the configured resource directory and access arbitrary files on the classpath or filesystem by using percent-encoded path separators. The flaw arises from decoding URL segments prior to validating them against directory escape patterns.
CVE-2026-61544 is a high-severity remote Denial of Service (DoS) vulnerability in libp2p-quic, the QUIC transport implementation of the official Rust networking stack for libp2p. It allows unauthenticated remote attackers to trigger an uncaught panic and crash listener applications.
An uncontrolled resource consumption vulnerability in the http4s Ember HTTP/2 server and client implementation leads to unauthenticated heap memory exhaustion and denial of service. The vulnerability stems from deferring frame size validation until the entire declared payload size is buffered.
CVE-2026-61554 is a high-severity uncontrolled resource consumption vulnerability in the http_poll transport component of the emp3r0r Command and Control (C2) framework. In affected versions prior to 4.2.5, the C2 server allocates session tracking resources, spawns execution routines, and routes incoming unauthenticated request bodies into the core dispatch engine before verifying the client's cryptographic authentication token. This logical ordering flaw allows unauthenticated remote attackers to exhaust critical host system resources and trigger a sustained denial of service.