Fedora Account System
Red Hat Associate
Red Hat Customer
HTTP/2 and HTTP/3 Extended CONNECT requests are downgraded as regular CONNECT requests A public GitHub Security Advisory (GHSA-w6j8-x45j-w75f) describes the following issue: ## Summary Netty's HTTP/2 and HTTP/3 HTTP-object conversion paths collapse Extended CONNECT requests into ordinary HTTP/1.1 `CONNECT` requests. An Extended CONNECT request such as: ```text :method: CONNECT :protocol: websocket :scheme: https :path: /admin/ws :authority: ws.example:443 ``` is converted to an HTTP/1.1 object shaped like: ```text CONNECT ws.example:443 HTTP/1.1 host: ws.example:443 x-http2-scheme: https ``` or, for HTTP/3: ```text CONNECT ws.example:443 HTTP/1.1 host: ws.example:443 x-http3-scheme: https ``` The converted request no longer carries the `:protocol` value or the Extended-CONNECT `:path`. A downstream handler using Netty's HTTP-object API therefore cannot distinguish this request from a regular CONNECT tunnel to `ws.example:443`. That is a semantic security boundary. RFC 8441 defines Extended CONNECT as a different CONNECT mode: the `:protocol` pseudo-header selects the protocol for the stream, `:path` remains part of the target URI, and the server must not treat `:authority` as the host to tunnel to in the same way it would for a regular CONNECT request. RFC 9220 applies the same pseudo-header and setting semantics to HTTP/3. ## Technical Details HTTP/2: - `codec-http2/.../HttpConversionUtil.java:272-280` uses `:authority` as the HTTP/1 request URI for every `CONNECT` request. - `codec-http2/.../HttpConversionUtil.java:328-337` creates a `DefaultHttpRequest` with that URI, then translates headers. - `codec-http2/.../HttpConversionUtil.java:806-813` maps `:authority` to Host and `:scheme` to `x-http2-scheme`, but does not preserve request `:path`; unrecognized pseudo-headers such as `:protocol` are dropped. HTTP/3: - `codec-http3/.../Http3HeadersSink.java:79-94` recognizes Extended CONNECT and requires `:method`, `:scheme`, `:authority`, `:path`, and `:protocol`. - `codec-http3/.../HttpConversionUtil.java:201-209` uses `:authority` as the HTTP/1 request URI for every `CONNECT` request. - `codec-http3/.../HttpConversionUtil.java:259-268` creates a `DefaultHttpRequest` with that URI, then translates headers. - `codec-http3/.../HttpConversionUtil.java:578-585` maps `:authority` to Host and `:scheme` to `x-http3-scheme`, but does not preserve request `:path`; `:protocol` is dropped as a pseudo-header. The resulting object-level shape is security-relevant because applications and gateway integrations commonly authorize CONNECT differently from WebSocket, WebTransport, MASQUE, or other Extended CONNECT protocols. With Netty's conversion path, a policy that permits regular CONNECT to an allowlisted authority can be applied to an Extended CONNECT request whose actual protocol and path were erased before application code sees it. ## Impact A remote HTTP/2 or HTTP/3 client can send an Extended CONNECT request that Netty presents to downstream HTTP-object handlers as a regular CONNECT tunnel. In gateway, proxy, application-server, or protocol-bridging deployments that use Netty's HTTP-object conversion path, this can bypass routing or authorization logic that is meant to distinguish: - regular CONNECT tunnels from WebSocket/WebTransport/MASQUE-style Extended CONNECT streams; - allowed CONNECT authorities from protected Extended-CONNECT paths; - enabled/registered Extended CONNECT protocols from ordinary CONNECT traffic. This report does not claim memory corruption, code execution, confidentiality impact, or impact on applications that never route HTTP/2 or HTTP/3 requests through Netty's HTTP-object adapters. The demonstrated impact is integrity loss through protocol-state confusion before application policy runs. ## Suggested Fix Recommended fix direction: - do not convert Extended CONNECT into an ordinary HTTP/1 `CONNECT` object without preserving the Extended-CONNECT state; - either reject Extended CONNECT in `HttpConversionUtil.toHttpRequest(...)` unless Netty can expose the state safely, or preserve it with explicit extension headers such as `x-http2-protocol` / `x-http3-protocol` and `x-http2-path` / `x-http3-path` for request conversion; - keep regular CONNECT behavior unchanged; - add regression tests covering direct conversion and the frame-to-object adapters for both HTTP/2 and HTTP/3; - add controls proving regular CONNECT and Extended CONNECT no longer produce the same HTTP-object shape. If maintainers prefer not to support Extended CONNECT through the HTTP-object API, the safest fix is to fail closed and require users to handle it at the native HTTP/2 or HTTP/3 frame/header layer. ## References - Netty security policy: https://github.com/netty/netty/security/policy - RFC 8441, Extended CONNECT: https://datatracker.ietf.org/doc/html/rfc8441#section-4 - RFC 9220, WebSockets over HTTP/3: https://datatracker.ietf.org/doc/html/rfc9220#section-3 - RFC 9113, HTTP/2 request pseudo-header fields: https://datatracker.ietf.org/doc/html/rfc9113#section-8.3.1 - RFC 9114, HTTP/3 request pseudo-header fields and CONNECT: https://datatracker.ietf.org/doc/html/rfc9114#section-4.3.1 - Go HTTP/2 Extended CONNECT implementation note requiring negotiation before use: https://go.dev/src/net/http/h2_bundle.go - Go issue discussing Extended CONNECT API concerns: https://github.com/golang/go/issues/27244 ## Affected Products - `io.netty:netty-codec-http2` - `io.netty:netty-codec-http3` Confirmed affected: - current `4.2` branch at `7bae566a93e69409697fe57fa807910ba5c9720e` - `netty-4.2.15.Final` at `a41f7b289ce1d697c50846f3ade3983e22b2ed40` - `netty-4.2.2.Final` at `660edeaefa` for HTTP/2 - `netty-4.2.0.Final` at `09e64d259c99` for HTTP/2 - `netty-4.1.135.Final` at `f05f765d81460799c53123a207f665bf3b465171` for HTTP/2 Suggested affected ranges: - `io.netty:netty-codec-http2 >= 4.1.64.Final, <= 4.1.135.Final` - `io.netty:netty-codec-http2 >= 4.2.0.Final, <= 4.2.15.Final` - `io.netty:netty-codec-http3 >= 4.2.8.Final, <= 4.2.15.Final` The HTTP/2 lower [truncated] Affected: - maven:io.netty:netty-codec-http2 affected >= 4.1.64.Final, <= 4.1.137.Final; fixed unknown - maven:io.netty:netty-codec-http2 affected >= 4.2.0.Final, <= 4.2.17.Final; fixed unknown - maven:io.netty:netty-codec-http3 affected >= 4.2.8.Final, <= 4.2.15.Final; fixed unknown Fixed versions: see advisory Advisory: https://github.com/netty/netty/security/advisories/GHSA-w6j8-x45j-w75f