GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-9998-894R-FWVR

Vulnerability from github – Published: 2026-09-15 19:54 – Updated: 2026-09-15 19:54
VLAI
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
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.23.34"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-ember-core_3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.23.35"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.23.34"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-ember-core_2.13"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.23.35"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.23.34"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-ember-core_2.12"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.23.35"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.0.0-M46"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-ember-core_2.13"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.0-M1"
            },
            {
              "fixed": "1.0.0-M47"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.0.0-M46"
      },
      "package": {
        "ecosystem": "Maven",
        "name": "org.http4s:http4s-ember-core_3"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.0-M1"
            },
            {
              "fixed": "1.0.0-M47"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-69205"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-444"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-15T19:54:25Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\n\nEmber\u0027s HTTP/1.1 header parser matches the `Transfer-Encoding` header value\nwith a case-sensitive substring test (`hValue.contains(\"chunked\")`). RFC\n9112 \u00a77 requires transfer-coding names to be compared case-insensitively. A\nrequest carrying `Transfer-Encoding: Chunked` (capital C) is therefore not\nrecognised as chunked, and Ember falls back to framing by `Content-Length`\n(or zero if absent) while a compliant intermediary frames the same bytes by\nchunked encoding. The two parsers then disagree on where the request body\nends, enabling HTTP request smuggling (TE.CL / TE.0).\n\nThe same line of code admits two further variants:\n\n- The substring test misfires on `Transfer-Encoding: notchunked` (an inverse\n  desync \u2014 Ember treats it as chunked while a compliant intermediary\n  rejects the unknown coding).\n- Header field bytes are decoded with the platform-default charset. Under\n  UTF-8 the wire bytes `E2 84 AA` decode to U+212A KELVIN SIGN, which\n  `String.equalsIgnoreCase` Unicode-case-folds to `k`, so\n  `Transfer-Encoding: chun\u003cU+212A\u003eed` matches `chunked` once the comparison\n  is made case-insensitive without also pinning the decode to ISO-8859-1.\n\n## Impact\n\n### Server\n\nRequest smuggling when ember-server is an origin behind an intermediary that\nhonours `Transfer-Encoding` case-insensitively per RFC, forwards the header\nvalue verbatim, and reuses keep-alive connections to the backend:\n\n- Front-end security bypass: the smuggled request reaches paths the\n  intermediary\u0027s ACL/auth layer would have blocked, with attacker-chosen\n  method and headers.\n- Cross-user request hijack: a partial smuggled prefix left in Ember\u0027s\n  connection buffer is concatenated with the next victim\u0027s request on the\n  same pooled backend connection, exposing its headers (e.g. `Cookie`,\n  `Authorization`) to the attacker.\n- Cache poisoning: the smuggled response is associated with the next request\n  key in a caching proxy.\n\n### Client\n\nember-client shares the same `HeaderP.parse` on the response path, enabling\nresponse smuggling when http4s is used as a gateway. This is less severe: it\nrequires a malicious or compromised upstream rather than an anonymous remote\nclient.\n\n## Preconditions\n\n- Unauthenticated remote attacker (server)\n- ember-server as origin behind a keep-alive intermediary\n- Intermediary treats `Transfer-Encoding` case-insensitively (per RFC) and\n  forwards the header value without lowercasing it\n- Malicious or compromised upstream (client)\n\n## Workarounds\n\n- Intermediary fully buffers and re-encodes request bodies (e.g. nginx with\n  default `proxy_request_buffering on`)\n- Intermediary normalises the `Transfer-Encoding` value (lowercases the\n  token) before forwarding\n- Disable backend keep-alive between the intermediary and Ember",
  "id": "GHSA-9998-894r-fwvr",
  "modified": "2026-09-15T19:54:25Z",
  "published": "2026-09-15T19:54:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/security/advisories/GHSA-9998-894r-fwvr"
    },
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/commit/5e88b2e7b4e6ea2f0c61040a4bc9de0d73e51217"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/http4s/http4s"
    },
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/releases/tag/v0.23.35"
    },
    {
      "type": "WEB",
      "url": "https://github.com/http4s/http4s/releases/tag/v1.0.0-M47"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Http4s Ember Transfer-Encoding value parsing (TE.CL / TE.0 request smuggling)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…