high · 8.7CVE-2026-69205Sep 15, 2026

CVE-2026-69205: http4s Ember Transfer-Encoding Case-Sensitive Parsing HTTP Request Smuggling

Shubham Kandhare
Security Engagement Manager, SecureLayer7

http4s Ember compared the Transfer-Encoding header value with a case-sensitive substring match, so a value like 'Chunked' (capital C) was silently ignored, letting an attacker trick a front-end proxy…

Packageorg.http4s:http4s-ember-core_3
Ecosystemmaven
Affected<= 0.23.34
Fixed in0.23.35
CVE-2026-69205: http4s Ember Transfer-Encoding Case-Sensitive Parsing HTTP Request Smuggling

The problem

Ember's HTTP/1.1 header parser in HeaderP.parse checked for chunked encoding using hValue.contains("chunked"), a case-sensitive substring test. RFC 9112 §7 requires transfer-coding names to be compared case-insensitively.

When Ember received Transfer-Encoding: Chunked, it did not recognise the value as chunked and fell back to framing by Content-Length (or zero if absent). A compliant intermediary in front of Ember would correctly treat the same request as chunked-encoded. The two parsers disagreed on message boundaries, enabling TE.CL and TE.0 request smuggling.

The same bug also admitted two further variants: the substring test fired on Transfer-Encoding: notchunked (inverse desync), and a Unicode Kelvin Sign (U+212A) could bypass the comparison once case-folding was applied.

Proof of concept

A working proof-of-concept for CVE-2026-69205 in org.http4s:http4s-ember-core_3, with the exact payload below.

http
POST /admin HTTP/1.1
Host: internal-app
Transfer-Encoding: Chunked
Content-Length: 4

1
Z
0

GET /private HTTP/1.1
Host: internal-app
Foo: bar

The front-end proxy sees Transfer-Encoding: Chunked and correctly frames the body as chunked (per RFC 9112), reading up to and including the terminating 0\r\n\r\n chunk. Ember's case-sensitive hValue.contains("chunked") test misses the capital-C value, so Ember falls back to Content-Length: 4 and reads exactly 4 bytes (1\r\nZ).

The remaining bytes, starting with GET /private, stay in Ember's read buffer and are prepended to the next pipelined or pooled request, smuggling it as an attacker-controlled request.

The patch replaces the raw substring test with a proper case-insensitive, RFC-compliant token comparison (CWE-444). After the fix, Chunked, CHUNKED, and any other capitalisation are all normalised before the check, closing all three variants described in the advisory.

The fix

Upgrade to org.http4s:http4s-ember-core_3 version **0.23.35** (or **1.0.0-M47** on the 1.x milestone series). The fix is in commit 5e88b2e7b4e6ea2f0c61040a4bc9de0d73e51217. If you cannot upgrade immediately, place a normalising intermediary in front of Ember that either fully buffers and re-encodes request bodies (nginx proxy_request_buffering on is the default), lowercases the Transfer-Encoding token before forwarding, or disables backend keep-alive so smuggled prefixes cannot bleed into the next connection.

Reported by reardonj and ERobertGII (security analysis and mitigations, acknowledged by Ross A. Baker).

References: [1][2][3][4][5]

Related research