Vulnerability GHSA-9998-894r-fwvr

High Risk
HIGH RISK
CVSS Score: 8.7
Score Range: 7.0–8.9
High severity vulnerabilities (CVSS 7.0–8.9). Serious vulnerabilities that should be prioritized soon after critical fixes.
3 hours ago
September 15, 2026 at 07:54 PM UTC
Http4s Ember Transfer-Encoding value parsing (TE.CL / TE.0 request smuggling)
0.10.0
0.10.0

Summary

Http4s Ember Transfer-Encoding value parsing (TE.CL / TE.0 request smuggling)

Details

Summary

Ember's HTTP/1.1 header parser matches the Transfer-Encoding header value with a case-sensitive substring test (hValue.contains("chunked")). RFC 9112 §7 requires transfer-coding names to be compared case-insensitively. A request carrying Transfer-Encoding: Chunked (capital C) is therefore not recognised as chunked, and Ember falls back to framing by Content-Length (or zero if absent) while a compliant intermediary frames the same bytes by chunked encoding. The two parsers then disagree on where the request body ends, enabling HTTP request smuggling (TE.CL / TE.0).

The same line of code admits two further variants:

  • The substring test misfires on Transfer-Encoding: notchunked (an inverse desync — Ember treats it as chunked while a compliant intermediary rejects the unknown coding).
  • Header field bytes are decoded with the platform-default charset. Under UTF-8 the wire bytes E2 84 AA decode to U+212A KELVIN SIGN, which String.equalsIgnoreCase Unicode-case-folds to k, so Transfer-Encoding: chun<U+212A>ed matches chunked once the comparison is made case-insensitive without also pinning the decode to ISO-8859-1.

Impact

Server

Request smuggling when ember-server is an origin behind an intermediary that honours Transfer-Encoding case-insensitively per RFC, forwards the header value verbatim, and reuses keep-alive connections to the backend:

  • Front-end security bypass: the smuggled request reaches paths the intermediary's ACL/auth layer would have blocked, with attacker-chosen method and headers.
  • Cross-user request hijack: a partial smuggled prefix left in Ember's connection buffer is concatenated with the next victim's request on the same pooled backend connection, exposing its headers (e.g. Cookie, Authorization) to the attacker.
  • Cache poisoning: the smuggled response is associated with the next request key in a caching proxy.

Client

ember-client shares the same HeaderP.parse on the response path, enabling response smuggling when http4s is used as a gateway. This is less severe: it requires a malicious or compromised upstream rather than an anonymous remote client.

Preconditions

  • Unauthenticated remote attacker (server)
  • ember-server as origin behind a keep-alive intermediary
  • Intermediary treats Transfer-Encoding case-insensitively (per RFC) and forwards the header value without lowercasing it
  • Malicious or compromised upstream (client)

Workarounds

  • Intermediary fully buffers and re-encodes request bodies (e.g. nginx with default proxy_request_buffering on)
  • Intermediary normalises the Transfer-Encoding value (lowercases the token) before forwarding
  • Disable backend keep-alive between the intermediary and Ember

Timeline

Published
3 hours ago
September 15, 2026 at 07:54 PM UTC
Fixed (0.23.35)
Unknown
Unknown
Fixed (0.23.35)
Unknown
Unknown
Fixed (1.0.0-M47)
Unknown
Unknown
Fixed (0.23.35)
Unknown
Unknown
Fixed (1.0.0-M47)
Unknown
Unknown
Last Modified
3 hours ago
September 15, 2026 at 08:00 PM UTC