REDHAT-BUG-2536955: Input Validation
HTTP/1 authority-form CONNECT is translated to malformed HTTP/2 CONNECT with Host-controlled :authority
A public GitHub Security Advisory (GHSA-45h4-vhwh-fmhg) describes the following issue:
Summary
Netty's HTTP/1-to-HTTP/2 conversion does not special-case true HTTP/1 CONNECT authority-form request-targets. Instead, HttpConversionUtil.toHttp2Headers() applies the generic request conversion path to a request-target like trusted.example:443.
For example:
text CONNECT trusted.example:443 HTTP/1.1 Host: attacker.example:443
is converted to HTTP/2 headers with these security-relevant properties:
text :method: CONNECT :authority: attacker.example:443 :scheme: trusted.example :path: <present>
The exact :path value has varied across releases (/ in checked older 4.2.x releases and trusted.example:443 in current/4.2.15), but the invariant bug is stable: the CONNECT tunnel authority is taken from the HTTP/1 Host header instead of the CONNECT authority-form request-target, and Netty emits HTTP/2 CONNECT-forbidden :scheme and :path pseudo-headers.
HTTP/2 CONNECT must omit :scheme and :path, and :authority must contain the host and port from the CONNECT authority-form request-target. In a Netty-based HTTP/1-to-HTTP/2 proxy or gateway, policy that authorizes the HTTP/1 CONNECT request-target can disagree with the upstream HTTP/2 proxy, which receives the Host-controlled :authority.
Technical Details
The relevant code is codec-http2/src/main/java/io/netty/handler/codec/http2/HttpConversionUtil.java. toHttp2Headers(HttpMessage, boolean) handles HttpRequest conversion with a generic URI/request-target parser:
text String host = inHeaders.getAsString(HttpHeaderNames.HOST); ... String requestTarget = request.uri(); out.path(toHttp2Path(requestTarget)); ... setHttp2Scheme(...); setHttp2Authority(host, out); out.method(request.method().asciiName());
For CONNECT, the HTTP/1 request-target is authority-form (host:port), not an origin-form path and not an absolute URI. On the current branch, trusted.example:443 is treated as a scheme-like string for :scheme, the request-target is emitted as :path, and the HTTP/1 Host header is used for :authority. On checked older 4.2.x releases, the :path value is /, but the authority confusion and forbidden pseudo-header emission still reproduce.
Impact
In a Netty HTTP/1-to-HTTP/2 proxy/gateway path, a remote HTTP/1 client can ask to CONNECT to one authority while supplying a different Host header. Netty then builds an HTTP/2 CONNECT request whose tunnel :authority is Host-controlled and whose pseudo-header set is malformed.
This can bypass tunnel allow-lists, egress policy, backend selection, audit logic, or other security controls that validate the HTTP/1 CONNECT request-target before forwarding over HTTP/2.
This report does not claim code execution or memory corruption. The impact is integrity loss through CONNECT tunnel-target confusion at an HTTP/1-to-HTTP/2 conversion boundary.
Suggested Fix
When converting true HTTP/1 authority-form CONNECT to HTTP/2:
- set :method to CONNECT; - set :authority from the HTTP/1 CONNECT request-target authority-form; - omit :scheme and :path; - reject or ignore conflicting Host instead of allowing it to replace the CONNECT target; - add regression tests for direct toHttp2Headers(...) and outbound HttpToHttp2ConnectionHandler conversion.
The attached patched-control diff demonstrates the minimal behavior change:
evidence/minimal-connect-patched-control.diff
The patched-control run passed:
fish ./mvnw -q -pl codec-http2 \ -Dtest=Http2ConnectAuthorityFormFixedControlTest,HttpToHttp2ConnectionHandlerTest#testAuthorityFormRequestTargetHandled \ -Dsurefire.failIfNoSpecifiedTests=false \ -DskipNativeTests -DskipAutobahnTests -Dmaven.antrun.skip=true test
Affected Package/Versions
io.netty:netty-codec-http2
Confirmed affected:
- current 4.2 branch at 7bae566a93e69409697fe57fa807910ba5c9720e - 4.2.15.Final at a41f7b289ce1d697c50846f3ade3983e22b2ed40 - 4.2.2.Final at 660edeaefad4a4cedbd61584e8f668ad2d89f0b8 - 4.2.0.Final at 09e64d259c99be8b5b2a471a78f11e65eb82598a - 4.1.135.Final at f05f765d81460799c53123a207f665bf3b465171
Suggested affected ranges:
- >= 4.1.0.Final, <= 4.1.135.Final - >= 4.2.0.Final, <= 4.2.15.Final
References
- Netty security policy: https://github.com/netty/netty/security/policy - RFC 9113 HTTP/2 CONNECT method: https://datatracker.ietf.org/doc/html/rfc9113#section-8.5 - RFC 9112 authority-form: https://datatracker.ietf.org/doc/html/rfc9112#section-3.2.3 - RFC 9110 CONNECT method: https://datatracker.ietf.org/doc/html/rfc9110#section-9.3.6
CWE and CVSS
Suggested CWEs:
- CWE-20: Improper Input Validation - CWE-436: Interpretation Conflict - CWE-444: Inconsistent Interpretation of HTTP Requests
Suggested CVSS v3.1:
text CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Suggested severity: High, score 7.5.
Rationale: a network peer can trigger this in a proxy/gateway path without authentication. Integrity impact is high because CONNECT can establish a tunnel to an unintended upstream authority when forwarding policy validated a different request-target.
Duplicate Boundary
Nearby reports are distinct:
- GHSA-cg2g-fxr4-mg8m: HTTP/1 absolute-form Host mismatch to HTTP/2 :authority. - GHSA-jgph-cgq3-c627: the sibling HTTP/1 CONNECT authority-form conversion bug in netty-codec-http3. - GHSA-w6j8-x45j-w75f: HTTP/2/HTTP/3 Extended CONNECT inbound downgrade. - GHSA-gcjj-c5ff-2m72, GHSA-xf5f-3m33-p8m3, and GHSA-w424-c27v-r9mr: HTTP/2-to-HTTP/1 inbound downgrade families.
This report covers outbound HTTP/1 CONNECT authority-form conversion to HTTP/2.
Live duplicate evidence is in evidence/advisory-duplicate-check.tsv.
Local PoV
PoV file:
pov/Http2ConnectAuthorityFormHostConfusionPovTest.java
Run from a Netty checkout after copying the PoV file into codec-http2/src/test/java/io/
[truncated]
Affected: - maven:io.netty:netty-codec-http2 affected >= 4.1.0.Final, <= 4.1.137.Final; fixed unknown - maven:io.netty:netty-codec-http2 affected >= 4.2.0.Final, <= 4.2.17.Final; fixed unknown
Fixed versions: see advisory
Advisory: https://github.com/netty/netty/security/advisories/GHSA-45h4-vhwh-fmhg
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
maven:io.netty:netty-codec-http2to a version that resolves this vulnerability.Fixed in 4.1.137.Final - Upgrade
Upgrade
maven:io.netty:netty-codec-http2to a version that resolves this vulnerability.Fixed in 4.2.17.Final - Configuration
Update/align Netty HTTP/1-to-HTTP/2 conversion logic (HttpConversionUtil / HttpToHttp2ConnectionHandler conversion) so that true HTTP/1 CONNECT authority-form targets are converted to HTTP/2 CONNECT correctly: do not emit forbidden `:scheme` and `:path` pseudo-headers; derive HTTP/2 `:authority` strictly from the HTTP/1 CONNECT request-target (`host:port`), and do not allow the HTTP/1 `Host` header to override a conflicting CONNECT target.
io.netty.handler.codec.http2.HttpConversionUtil CONNECT HTTP/2 pseudo-headers mapping = For HTTP/1 CONNECT authority-form request-target: omit `:scheme` and `:path`; set `:authority` from the HTTP/1 CONNECT request-target authority-form; set `:method` to `CONNECT`; reject or ignore conflicting `Host` header instead of allowing it to replace the CONNECT target - Compensating control
In an HTTP/1-to-HTTP/2 proxy/gateway, ensure tunnel allow-lists/egress policy and backend selection are enforced on the CONNECT authority-form request-target and that a conflicting HTTP/1 `Host` header cannot influence the upstream HTTP/2 `:authority`.
Event History
Frequently Asked Questions
What does an attacker need to send to trigger the incorrect conversion?
The attacker needs an HTTP/1.1 CONNECT request using an authority-form target and a Host header that names a different authority. For example, the request target can be trusted.example:443 while the Host header is attacker.example:443.
How can I identify affected conversions in request traces?
Inspect the HTTP/2 headers produced from HTTP/1 CONNECT requests. An affected conversion uses the HTTP/1 Host value for :authority and includes :scheme and :path, even though HTTP/2 CONNECT must omit :scheme and :path and use the CONNECT request-target as :authority.