Skip to content

HTTP/2 and HTTP/3 Extended CONNECT requests are downgraded as regular CONNECT requests

High
chrisvest published GHSA-w6j8-x45j-w75f Sep 10, 2026

Package

maven io.netty:netty-codec-http2 (Maven)

Affected versions

>= 4.1.64.Final, <= 4.1.137.Final
>= 4.2.0.Final, <= 4.2.17.Final

Patched versions

4.1.138.Final
4.2.18.Final
maven io.netty:netty-codec-http3 (Maven)
>= 4.2.8.Final, <= 4.2.15.Final
4.2.18.Final

Description

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:

:method: CONNECT
:protocol: websocket
:scheme: https
:path: /admin/ws
:authority: ws.example:443

is converted to an HTTP/1.1 object shaped like:

CONNECT ws.example:443 HTTP/1.1
host: ws.example:443
x-http2-scheme: https

or, for HTTP/3:

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

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 bound is the first 4.1 tag containing Netty's Http2Headers.PseudoHeaderName.PROTOCOL support. The HTTP/3 lower bound is the first 4.2 tag containing Netty's HTTP/3 :protocol support.

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:

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 the issue without authentication or user interaction, and the failure occurs before downstream policy receives the request. The claimed impact is integrity because the converted HTTP object can cause authorization or routing policy to evaluate the wrong protocol state. Medium may also be defensible if maintainers scope HTTP-object Extended CONNECT handling as an opt-in compatibility feature rather than a default security boundary.

Duplicate Boundary

Live Netty private-advisory research found adjacent authority-family reports, but no report covering Extended CONNECT :protocol / :path erasure:

  • GHSA-w424-c27v-r9mr: HTTP/2 :authority userinfo forwarded as Host.
  • GHSA-xf5f-3m33-p8m3: HTTP/2 :authority plus Host duplicate downgrade.
  • GHSA-w2m9-rvg6-gfxg: HTTP/3 :authority userinfo forwarded as Host.
  • GHSA-qf63-3vvr-7272: HTTP/3 :authority plus Host duplicate downgrade.
  • GHSA-h235-6gmg-jv93: HTTP/3 absolute-form :path authority confusion.

This report is distinct because the root cause is not malformed authority text or conflicting Host values. The root cause is that a valid Extended CONNECT state is normalized into a regular CONNECT state by dropping :protocol and the Extended-CONNECT path.

Local PoVs

PoV files:

  • pov/Http2ExtendedConnectDowngradePovTest.java
  • pov/Http3ExtendedConnectDowngradePovTest.java

Run from a Netty checkout after copying each PoV to the matching test package:

./mvnw -q -pl codec-http2 \
  -Dtest=Http2ExtendedConnectDowngradePovTest \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -DskipNativeTests -DskipAutobahnTests -Dmaven.antrun.skip=true test
./mvnw -q -pl codec-http3 \
  -Dtest=Http3ExtendedConnectDowngradePovTest \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -DskipNativeTests -DskipAutobahnTests -Dmaven.antrun.skip=true test

The PoVs are local-only. They do not contact any third-party host.

Each PoV proves:

  • an Extended CONNECT request with :protocol=websocket, :path=/admin/ws, and :authority=ws.example:443 becomes CONNECT ws.example:443;
  • Host is also ws.example:443;
  • the converted HTTP object lacks both the Extended-CONNECT path and protocol;
  • a regular-CONNECT allowlist sees the converted object as acceptable;
  • a protocol-aware policy using the original pseudo-headers would reject the same request.

Observed results:

codec-http2 current 4.2 head: Tests run: 2, Failures: 0, Errors: 0
codec-http2 4.2.15.Final:    Tests run: 2, Failures: 0, Errors: 0
codec-http2 4.2.2.Final:     Tests run: 2, Failures: 0, Errors: 0
codec-http2 4.2.0.Final:     Tests run: 2, Failures: 0, Errors: 0
codec-http2 4.1.135.Final:   Tests run: 2, Failures: 0, Errors: 0

codec-http3 current 4.2 head: Tests run: 2, Failures: 0, Errors: 0
codec-http3 4.2.15.Final:    Tests run: 2, Failures: 0, Errors: 0
codec-http3 4.2.2.Final:     not applicable; HTTP/3 :protocol support absent

Patched-control evidence is included in:

  • evidence/minimal-fail-closed-patched-control.diff
  • pov/Http2ExtendedConnectFixedControlTest.java
  • pov/Http3ExtendedConnectFixedControlTest.java
  • evidence/patched-control-results.txt

The patched control uses a minimal fail-closed guard: if a CONNECT request contains :protocol, the HTTP/1 conversion path rejects it instead of creating an ordinary CONNECT object. Regular CONNECT remains accepted. Both fixed-control tests passed on current 4.2 head:

codec-http2 patched control: Tests run: 2, Failures: 0, Errors: 0
codec-http3 patched control: Tests run: 2, Failures: 0, Errors: 0

Why This Is Not Intended Safe Behavior

This is not merely an application trust-model issue. Netty exposes HTTP/2 and HTTP/3 adapters that convert protocol-native request metadata into the long-standing HTTP-object API. Those adapters already preserve selected protocol metadata in extension headers such as x-http2-scheme, x-http3-scheme, stream ids, and pushed-stream ids. For Extended CONNECT, the adapter silently discards the metadata that defines the security-sensitive difference between regular CONNECT and Extended CONNECT.

RFC 8441 explicitly changes CONNECT semantics when :protocol is present: the server is not supposed to create a normal tunnel to the host indicated by :authority. RFC 9220 says HTTP/3 uses the same pseudo-header and setting semantics. Netty's conversion does the opposite at the object layer by producing an ordinary CONNECT request-target equal to :authority.

The control case confirms regular CONNECT itself is not the issue. A regular CONNECT request without :protocol and :path produces the same HTTP/1 object shape that the Extended CONNECT request produces. The bug is that these two different protocol states become indistinguishable after conversion.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

CVE ID

CVE-2026-93568

Weaknesses

Improper Input Validation

The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly. Learn more on MITRE.

Interpretation Conflict

Product A handles inputs or steps differently than Product B, which causes A to perform incorrect actions based on its perception of B's state. Learn more on MITRE.

Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling')

The product acts as an intermediary HTTP agent (such as a proxy or firewall) in the data flow between two entities such as a client and server, but it does not interpret malformed HTTP requests or responses in ways that are consistent with how the messages will be processed by those entities that are at the ultimate destination. Learn more on MITRE.

Credits