CVE-2026-93573: Io.netty/netty-codec-http: netty split transfer-encoding fields bypass final-chunked validation and enable request smuggling
A flaw was found in Netty's HTTP/1.1 decoder. This vulnerability allows a remote attacker to bypass Transfer-Encoding header validation by splitting the Transfer-Encoding field across multiple headers, with the last field containing a non-final transfer coding like gzip or deflate. This bypass can lead to HTTP request smuggling, enabling attackers to bypass security controls, desynchronize request processing, or cause requests to be processed in an unintended context.
Other sources
Netty split Transfer-Encoding fields bypass final-chunked validation and enable request smuggling
A public GitHub Security Advisory (GHSA-3jrc-fchc-59pw) describes the following issue:
Summary
pov: pov-test
Netty's HTTP/1.1 decoder added RFC 9112 validation for malformed Transfer-Encoding order in the fix family for GHSA-38f8-5428-x5cv / CVE-2026-42585. That validation rejects the single-field case Transfer-Encoding: chunked, identity, but it can be bypassed when equivalent ordering is expressed as multiple header fields and the last field value is a short non-final transfer coding such as gzip or deflate.
For example:
text Transfer-Encoding: chunked Transfer-Encoding: gzip
is equivalent to the combined field value:
text Transfer-Encoding: chunked, gzip
In that value, chunked is not the final transfer coding. A request recipient must reject this message under RFC 9112 framing rules. Netty instead treats the message as chunked, accepts the terminating zero-size chunk, and parses a following request as a second request on the same connection.
This creates an HTTP request-smuggling primitive when Netty is paired with an intermediary or peer that rejects, buffers, or differently interprets the same invalid transfer-coding order.
This should be triaged as a current supported-release bypass/incomplete fix in the malformed Transfer-Encoding family. It is not a claim that malformed split Transfer-Encoding risk was never discussed publicly: Netty issue #9861 raised closely related behavior in 2019, and the May 2026 GHSA-38f8-5428-x5cv advisory fixed a single-field instance of the same ordering rule. The current issue is that latest supported releases still accept the split-field form after those fixes.
Technical Details
HttpUtil.isTransferEncodingChunked(...) returns true if any Transfer-Encoding field contains the comma-separated token chunked:
text codec-http/src/main/java/io/netty/handler/codec/http/HttpUtil.java:362 codec-http/src/main/java/io/netty/handler/codec/http/HttpUtil.java:363
HttpHeaders.containsValue(...) checks comma-separated values across header fields:
text codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java:1600 codec-http/src/main/java/io/netty/handler/codec/http/HttpHeaders.java:1603
Once any chunked value is found, HttpObjectDecoder enters chunked decoding. It then validates only the final Transfer-Encoding field value:
text codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:853 codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:859 codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:861
The validation has a length guard:
text codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:863 codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:865 codec-http/src/main/java/io/netty/handler/codec/http/HttpObjectDecoder.java:867
The comment says that if the final value is not longer than chunked, Netty knows it is only chunked. That assumption is false for final values like gzip and deflate. As a result:
- Transfer-Encoding: chunked, identity is rejected. - Transfer-Encoding: chunked followed by Transfer-Encoding: gzip is accepted. - Transfer-Encoding: chunked followed by Transfer-Encoding: deflate is accepted.
Git blame ties this validation block to the May 4, 2026 hardening commit:
text 977661f71f7511ad68ca17cabd7b5185efb978f4 Motivation: RFC9112 specified that chunked must be the last encoding so we should verify this.
PoC
Run the local PoV:
fish cd oss-zero-day-harness bash submission-bundle/netty-pov-test-transfer-encoding-order-bypass/poc/reproduce.sh
The key request shape is:
text POST /one HTTP/1.1\r\n Host: target\r\n Transfer-Encoding: chunked\r\n Transfer-Encoding: gzip\r\n \r\n 0\r\n \r\n GET /two HTTP/1.1\r\n Host: target\r\n \r\n
Observed on current 4.2:
text CASE splitfieldschunkedthengzipaccepted request uri=/one result=success transferEncoding=[chunked, gzip] lastContent bytes=0 result=success request uri=/two result=success transferEncoding=[] lastContent bytes=0 result=success
The same run confirms the patched single-field case is rejected:
text CASE singlefieldchunkedthenidentityrejected request uri=/one result=failure(java.lang.IllegalArgumentException:chunked must be the last encoding present in the Transfer-Encoding header) transferEncoding=[chunked, identity]
The supplementary Content-Length case is rejected on current 4.2:
text CASE splitfieldschunkedthengzipwithcontentlengthrejected request uri=/one result=failure(io.netty.handler.codec.http.ContentLengthNotAllowedException:Content-Length are not allowed in HTTP/1.1 messages that contains a Transfer-Encoding header.) transferEncoding=[chunked, gzip]
Impact
HTTP request smuggling can bypass front-end routing and access-control decisions, desynchronize request processing, or cause a following request to be processed in an unintended context. The exploitability of this primitive depends on a deployment with a parser differential, but Netty is the component that accepts the malformed framing and splits the stream into two requests.
The included PoV also checks a Content-Length variant. Current Netty rejects split Transfer-Encoding plus Content-Length with ContentLengthNotAllowedException. This report therefore does not claim the exact CL.TE exploitation shape from GHSA-38f8-5428-x5cv; it claims the TE-only split-field final-coding bypass that remains in current supported releases.
The PoV is local-only. It uses EmbeddedChannel and HttpRequestDecoder; it does not contact any live service.
Suggested Fix
Parse Transfer-Encoding as one ordered list across all field lines before deciding whether to enter chunked decoding. The decoder should reject HTTP/1.1 requests when the final transfer-coding to
[truncated]
Affected: - maven:io.netty:netty-codec-http affected >=4.2.12.Final; fixed unknown - maven:io.netty:netty-codec-http affected >=4.1.132.Final; fixed unknown
Fixed versions: see advisory
Advisory: https://github.com/netty/netty/security/advisories/GHSA-3jrc-fchc-59pw
— Red Hat
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
maven:io.netty:netty-codec-httpto a version that resolves this vulnerability.Fixed in 4.1.132.Final - Upgrade
Upgrade
maven:io.netty:netty-codec-httpto a version that resolves this vulnerability.Fixed in 4.2.12.Final - Compensating control
Add/adjust upstream HTTP request validation (front-end/proxy/WAF/parser) to reject malformed HTTP/1.1 framing where multiple Transfer-Encoding header fields encode an ordering where the final transfer-coding is not valid under RFC 9112 (e.g., cases like split "Transfer-Encoding: chunked" with a later field containing a non-final coding such as "gzip" or "deflate").
Event History
Frequently Asked Questions
What request pattern is needed to trigger the issue?
An attacker can send an HTTP/1.1 request with Transfer-Encoding split across multiple header fields so that chunked is followed by a non-final coding in a later field, such as "Transfer-Encoding: chunked" followed by "Transfer-Encoding: gzip" or "deflate". Netty accepts the zero-size chunk terminator and can parse subsequent bytes as a second request on the same connection.
Does exploitation require authentication or user interaction?
No. The supplied severity vector indicates network-based exploitation with low attack complexity, no privileges required, and no user interaction.
What security impact can request smuggling have in this case?
The supplied severity vector indicates low confidentiality and low integrity impact, with no availability impact. The described behavior allows a following request to be parsed on the same connection after the malformed Transfer-Encoding sequence is accepted.
How can I check whether traffic is attempting to exploit this issue?
Inspect HTTP/1.1 requests for multiple Transfer-Encoding header fields where an earlier field contains chunked and a later field contains another transfer coding, such as gzip or deflate. These fields combine into an invalid ordering in which chunked is not the final transfer coding.