GHSA-7P3P-8QV8-M2VH
Vulnerability from github – Published: 2026-07-22 22:56 – Updated: 2026-07-22 22:56Summary
Jetty currently accepts HTTP/2 and HTTP/3 requests where the regular Host header and the pseudo-header :authority do not match. As a result, the same request can carry two different host identities through Jetty:
- logic based on
HttpURI/Request.getServerName(request)uses:authority - logic based on raw request headers continues to use
Host
This creates a host/authority confusion condition that can break security assumptions in higher layers.
Jetty already performs an explicit authority/Host consistency check on the HTTP/1.1 path, but equivalent validation is missing on the HTTP/2 and HTTP/3 paths.
Security Impact
This issue is not inherently remote code execution, but it can become security-relevant in deployments that rely on the request host for security-sensitive decisions, including:
- host-based access control
- virtual host isolation
- multi-tenant routing by hostname
- login/logout/callback URL construction
- reverse proxy and forwarded-header trust chains
- auditing, cache keys, and absolute URL generation
Potential consequences include:
- bypass of host-based ACLs
- virtual host or tenant isolation failures
- incorrect or attacker-influenced redirect/callback targets
- inconsistent proxy/downstream interpretation of the original target host
- misleading logs and audit records
Technical Root Cause
-
On the HTTP/2 and HTTP/3 metadata builder paths:
-
:authorityis parsed separately into authority/URI state Hostis preserved as a normal request header-
the two values are not compared for consistency
-
On the HTTP/2 and HTTP/3 server entry paths:
-
Jetty calls
ComplianceUtils.verify(httpCompliance, requestMetaData, listener) -
this verification does not enforce
MISMATCHED_AUTHORITY -
On the HTTP/1.1 path:
-
Jetty explicitly checks whether authority and
Hostmatch - mismatches are rejected by default
Relevant Code Locations
HTTP/2 metadata builder:
jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/internal/MetaDataBuilder.java
HTTP/3 metadata builder:
jetty-core/jetty-http3/jetty-http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/internal/metadata/MetaDataBuilder.java
HTTP/2 server entry:
jetty-core/jetty-http2/jetty-http2-server/src/main/java/org/eclipse/jetty/http2/server/internal/HttpStreamOverHTTP2.java
HTTP/3 server entry:
jetty-core/jetty-http3/jetty-http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpStreamOverHTTP3.java
Shared HTTP compliance verification:
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/ComplianceUtils.java
HTTP/1.1 authority/Host consistency check:
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
Defined but not enforced on H2/H3:
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java- violation: MISMATCHED_AUTHORITY
Reproduction
I reproduced this on local Jetty 12.1.9-SNAPSHOT source.
Minimal reproduction steps:
- Start a Jetty HTTP/2 or HTTP/3 test server.
- Send a request with:
- :authority = localhost:
- Host = evil.example:
- In the request handler, inspect both:
- Request.getServerName(request)
- request.getHeaders().get(HttpHeader.HOST)
- Observe whether Jetty rejects the request or allows both values to remain visible.
Observed result:
- HTTP/2: request is accepted and returns 200
- HTTP/3: request is accepted and returns 200
- the server can observe both:
- serverName=localhost
- hostHeader=evil.example:
This shows that a single attacker-controlled request can preserve two conflicting host interpretations inside Jetty.
Tests Used
HTTP/2 rejection test:
org.eclipse.jetty.http2.tests.HTTP2Test#testRejectMismatchedHostHeaderAndAuthority
HTTP/2 exploitability test:
org.eclipse.jetty.http2.tests.HTTP2Test#testMismatchedHostHeaderAndAuthoritySplitsAuthorityFromHostHeader
HTTP/3 rejection test:
org.eclipse.jetty.http3.tests.HandlerClientServerTest#testRejectMismatchedHostHeaderAndAuthority
HTTP/3 exploitability test:
org.eclipse.jetty.http3.tests.HandlerClientServerTest#testMismatchedHostHeaderAndAuthoritySplitsAuthorityFromHostHeader
Observed behavior:
- both rejection tests fail because Jetty returns 200 instead of 400
- both exploitability tests pass, confirming that Jetty exposes different host values to different layers
Project-Internal Evidence of Real Impact
Examples:
jetty-openidusesRequest.getServerName(request)to construct redirect URLsjetty-ee11-proxyuses the rawHostheader when buildingForwarded
This indicates that the issue is not merely theoretical: Jetty’s own ecosystem already contains code paths where different host sources are used for different purposes.
Affected Version
Confirmed affected version:
- 12.1.9-SNAPSHOT
Other versions may also be affected if they share the same HTTP/2 / HTTP/3 request construction and compliance-validation logic. I have not yet completed a historical version matrix and would recommend confirming exact affected ranges from Jetty’s branch history.
Suggested Fix
Recommend adding HTTP/2 and HTTP/3 validation equivalent to the existing HTTP/1.1 authority/Host consistency check:
- if both :authority and regular Host are present
- normalize and compare them
- if they do not match, reject the request with 400 Bad Request
- route the failure through the existing MISMATCHED_AUTHORITY compliance mechanism
Also adding explicit HTTP/2 and HTTP/3 regression coverage for this case.
Disclosure Status
- not publicly disclosed
- no public issue filed
- shared only privately with the Jetty security contacts
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.eclipse.jetty:jetty-server"
},
"ranges": [
{
"events": [
{
"introduced": "9.4.0.v20161208"
},
{
"last_affected": "9.4.58.v20250814"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.eclipse.jetty:jetty-server"
},
"ranges": [
{
"events": [
{
"introduced": "10.0.0"
},
{
"last_affected": "10.0.26"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.eclipse.jetty:jetty-server"
},
"ranges": [
{
"events": [
{
"introduced": "11.0.0"
},
{
"last_affected": "11.0.26"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 12.0.34"
},
"package": {
"ecosystem": "Maven",
"name": "org.eclipse.jetty:jetty-server"
},
"ranges": [
{
"events": [
{
"introduced": "12.0.0"
},
{
"fixed": "12.0.35"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 12.1.8"
},
"package": {
"ecosystem": "Maven",
"name": "org.eclipse.jetty:jetty-server"
},
"ranges": [
{
"events": [
{
"introduced": "12.1.0"
},
{
"fixed": "12.1.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-6790"
],
"database_specific": {
"cwe_ids": [
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T22:56:43Z",
"nvd_published_at": "2026-07-14T09:16:41Z",
"severity": "MODERATE"
},
"details": "#### Summary\n\nJetty currently accepts HTTP/2 and HTTP/3 requests where the regular\nHost header and the pseudo-header :authority\ndo not match. As a result, the same request can carry two different host identities\nthrough Jetty:\n\n- logic based on `HttpURI` / `Request.getServerName(request)` uses `:authority`\n- logic based on raw request headers continues to use `Host`\n\nThis creates a host/authority confusion condition that can break\nsecurity assumptions in higher layers.\n\nJetty already performs an explicit authority/Host consistency check on\nthe HTTP/1.1 path, but equivalent validation is missing on the HTTP/2\nand HTTP/3 paths.\n\n#### Security Impact\n\nThis issue is not inherently remote code execution, but it can become\nsecurity-relevant in deployments that rely on the request host for\nsecurity-sensitive decisions, including:\n\n- host-based access control\n- virtual host isolation\n- multi-tenant routing by hostname\n- login/logout/callback URL construction\n- reverse proxy and forwarded-header trust chains\n- auditing, cache keys, and absolute URL generation\n\nPotential consequences include:\n\n- bypass of host-based ACLs\n- virtual host or tenant isolation failures\n- incorrect or attacker-influenced redirect/callback targets\n- inconsistent proxy/downstream interpretation of the original target host\n- misleading logs and audit records\n\n#### Technical Root Cause\n\n1. On the HTTP/2 and HTTP/3 metadata builder paths:\n\n- `:authority` is parsed separately into authority/URI state\n- `Host` is preserved as a normal request header\n- the two values are not compared for consistency\n\n2. On the HTTP/2 and HTTP/3 server entry paths:\n\n- Jetty calls `ComplianceUtils.verify(httpCompliance, requestMetaData, listener)`\n- this verification does not enforce `MISMATCHED_AUTHORITY`\n\n3. On the HTTP/1.1 path:\n\n- Jetty explicitly checks whether authority and `Host` match\n- mismatches are rejected by default\n\n#### Relevant Code Locations\n\nHTTP/2 metadata builder:\n\n- `jetty-core/jetty-http2/jetty-http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/internal/MetaDataBuilder.java`\n\nHTTP/3 metadata builder:\n\n- `jetty-core/jetty-http3/jetty-http3-qpack/src/main/java/org/eclipse/jetty/http3/qpack/internal/metadata/MetaDataBuilder.java`\n\nHTTP/2 server entry:\n\n- `jetty-core/jetty-http2/jetty-http2-server/src/main/java/org/eclipse/jetty/http2/server/internal/HttpStreamOverHTTP2.java`\n\nHTTP/3 server entry:\n\n- `jetty-core/jetty-http3/jetty-http3-server/src/main/java/org/eclipse/jetty/http3/server/internal/HttpStreamOverHTTP3.java`\n\nShared HTTP compliance verification:\n\n- `jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/ComplianceUtils.java`\n\nHTTP/1.1 authority/Host consistency check:\n\n- `jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java`\n\nDefined but not enforced on H2/H3:\n\n- `jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java`\n- violation: MISMATCHED_AUTHORITY\n\n#### Reproduction\n\nI reproduced this on local Jetty 12.1.9-SNAPSHOT source.\n\nMinimal reproduction steps:\n\n1. Start a Jetty HTTP/2 or HTTP/3 test server.\n2. Send a request with:\n - :authority = localhost:\u003cport\u003e\n - Host = evil.example:\u003cport\u003e\n3. In the request handler, inspect both:\n - Request.getServerName(request)\n - request.getHeaders().get(HttpHeader.HOST)\n4. Observe whether Jetty rejects the request or allows both values to remain visible.\nObserved result:\n - HTTP/2: request is accepted and returns 200\n - HTTP/3: request is accepted and returns 200\n - the server can observe both:\n - serverName=localhost\n - hostHeader=evil.example:\u003cport\u003e\n\nThis shows that a single attacker-controlled request can preserve two conflicting host interpretations inside Jetty.\n\n#### Tests Used\n\n\nHTTP/2 rejection test:\n\n- `org.eclipse.jetty.http2.tests.HTTP2Test#testRejectMismatchedHostHeaderAndAuthority`\n\nHTTP/2 exploitability test:\n\n- `org.eclipse.jetty.http2.tests.HTTP2Test#testMismatchedHostHeaderAndAuthoritySplitsAuthorityFromHostHeader`\n\nHTTP/3 rejection test:\n\n- `org.eclipse.jetty.http3.tests.HandlerClientServerTest#testRejectMismatchedHostHeaderAndAuthority`\n\nHTTP/3 exploitability test:\n\n- `org.eclipse.jetty.http3.tests.HandlerClientServerTest#testMismatchedHostHeaderAndAuthoritySplitsAuthorityFromHostHeader`\n\n\nObserved behavior:\n\n- both rejection tests fail because Jetty returns 200 instead of 400\n- both exploitability tests pass, confirming that Jetty exposes different host values to different layers\n\n#### Project-Internal Evidence of Real Impact\n\nExamples:\n\n- `jetty-openid` uses `Request.getServerName(request)` to construct redirect URLs\n- `jetty-ee11-proxy` uses the raw `Host` header when building `Forwarded`\n\nThis indicates that the issue is not merely theoretical: Jetty\u2019s own\necosystem already contains code paths where different host sources are\nused for different purposes.\n\n#### Affected Version\n\nConfirmed affected version:\n\n- 12.1.9-SNAPSHOT\n\nOther versions may also be affected if they share the same HTTP/2 /\nHTTP/3 request construction and compliance-validation logic. I have\nnot yet completed a historical version matrix and would recommend\nconfirming exact affected ranges from Jetty\u2019s branch history.\n\n\n#### Suggested Fix\n\nRecommend adding HTTP/2 and HTTP/3 validation equivalent to the\nexisting HTTP/1.1 authority/Host consistency check:\n\n- if both :authority and regular Host are present\n - normalize and compare them\n - if they do not match, reject the request with 400 Bad Request\n - route the failure through the existing MISMATCHED_AUTHORITY compliance mechanism\n\nAlso adding explicit HTTP/2 and HTTP/3 regression coverage for this case.\n\n#### Disclosure Status\n\n- not publicly disclosed\n- no public issue filed\n- shared only privately with the Jetty security contacts",
"id": "GHSA-7p3p-8qv8-m2vh",
"modified": "2026-07-22T22:56:43Z",
"published": "2026-07-22T22:56:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/security/advisories/GHSA-7p3p-8qv8-m2vh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-6790"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/issues/14870"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/pull/14871"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/pull/14897"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/pull/14970"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/commit/3e5a4daec196859b8886b6f67b1157dab47cdb6f"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/commit/67ba9e6b39661810123680d9c894e99a7940c73d"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/commit/cbca3076f7c914a232e7a8b22fa95fbf7e67a6cc"
},
{
"type": "PACKAGE",
"url": "https://github.com/jetty/jetty.project"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/releases/tag/jetty-12.0.35"
},
{
"type": "WEB",
"url": "https://github.com/jetty/jetty.project/releases/tag/jetty-12.1.9"
},
{
"type": "WEB",
"url": "https://gitlab.eclipse.org/security/cve-assignment/-/work_items/99"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Eclipse Jetty: HTTP Authority/Host mismatch"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.