Fedora Account System
Red Hat Associate
Red Hat Customer
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 split_fields_chunked_then_gzip_accepted 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 single_field_chunked_then_identity_rejected 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 split_fields_chunked_then_gzip_with_content_length_rejected 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