Bug 2536955 (CVE-2026-93567) - CVE-2026-93567 io.netty/netty-codec-http2: HTTP/1 authority-form CONNECT is translated to malformed HTTP/2 CONNECT with Host-controlled :authority
Summary: CVE-2026-93567 io.netty/netty-codec-http2: HTTP/1 authority-form CONNECT is t...
Keywords:
Status: NEW
Alias: CVE-2026-93567
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-09-18 10:02 UTC by OSIDB Bzimport
Modified: 2026-09-18 20:01 UTC (History)
66 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-09-18 10:02:32 UTC
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


Note You need to log in before you can comment on or make changes to this bug.