Jul 23, 2026·5 min read·92 visits
Eclipse Jetty's HTTP/2 and HTTP/3 pipelines fail to verify that the ':authority' pseudo-header matches the 'Host' header, leading to host-confusion, proxy bypass, and virtual host escapes.
A host/authority desynchronization vulnerability exists in Eclipse Jetty's handling of HTTP/2 and HTTP/3 requests. When both an ':authority' pseudo-header and a standard 'Host' header are present in a request, Jetty fails to validate that they represent the same target host. This desynchronization creates a host-confusion or 'split-brain' state, enabling attackers to bypass access control lists, escape virtual host isolation, poison web caches, or manipulate redirect targets in backend applications.
Eclipse Jetty fails to validate that the HTTP/2 and HTTP/3 request authority, provided via the :authority pseudo-header, matches the standard HTTP Host header. This omission violates strict host/authority alignment mandates set forth in modern specifications, namely RFC 9110, RFC 9112, RFC 9113, and RFC 9114.\n\nHistorically, earlier specifications like RFC 2616 did not strictly enforce this consistency check. Consequently, legacy software architectures frequently permitted divergent values. Modern web infrastructures, however, rely heavily on matching hosts for virtual hosting, logging, access control, and URI construction, making this desynchronization a security concern.\n\nWithout strict matching, Jetty enters a split-brain state where the servlet API uses the pseudo-header value for internal routing, while down-stream applications or proxies parse the raw Host header. This discrepancy opens a vector for host-evasion attacks across multiple protocols.
The root cause lies in how Jetty processes pseudo-headers in HTTP/2 and HTTP/3 requests. The :authority pseudo-header is parsed and mapped directly to the internal HttpURI state of the request, which API calls like Request.getServerName() rely on. However, the Host header is preserved as a standard header in the HTTP request map without cross-verification.\n\nWhile Jetty's HTTP/1.1 implementation contained verification steps to ensure consistency between target host authorities and the Host header, this validation logic was completely bypassed during HTTP/2 and HTTP/3 parsing. The MetaDataBuilder implementations for both protocols failed to align the :authority pseudo-header and the Host header, treating them as separate variables.\n\nThis desynchronization manifests when a client supplies conflicting values in :authority and Host headers. If an intermediate reverse proxy forwards the request without normalizing these parameters, the container evaluates access control lists based on one value while application business logic processes the other, subverting architectural boundaries.
The vulnerability was resolved by refactoring the verification mechanism out of protocol-specific layers and moving it directly into the central dispatch flow. The fix, introduced in commit 67ba9e6b39661810123680d9c894e99a7940c73d, establishes centralized checks via ComplianceUtils.verify() within the core HttpChannelState pipeline.\n\nThe logic extracts the host and port segments from the HttpURI representing the parsed pseudo-header and compares them with the extracted values from the standard Host header using authorityMatches(). The following code block demonstrates this validation flow:\n\njava\n// Centralized verification logic from ComplianceUtils.java\npublic static void verify(HttpURI httpURI, HttpFields requestHeaders, HttpCompliance httpCompliance, ComplianceViolation.Listener listener)\n{\n // ... [validation setup] ...\n if (!authorityMatches(httpURI, requestHeaders.get(HttpHeader.HOST)))\n {\n // Verify if compliance configuration allows mismatched authorities\n if (!ComplianceUtils.allows(httpCompliance, HttpCompliance.Violation.MISMATCHED_AUTHORITY, \"Authority!=Host\", listener))\n throw new HttpException.RuntimeException(HttpStatus.BAD_REQUEST_400, \"Authority!=Host\");\n }\n}\n\n\nThe check evaluates the effective port configuration of both inputs, resolving default ports (such as port 80 for HTTP or 443 for HTTPS) using URIUtil.getDefaultPortForScheme(). A case-insensitive comparison is then executed on the hostname to ensure structural identity. If a mismatch is detected, Jetty raises a 400 Bad Request exception under strict compliance profiles.
To trigger the vulnerability, an attacker must construct an HTTP/2 or HTTP/3 request specifying conflicting values in the :authority pseudo-header and the standard Host header. The attacker requires direct network access to either the Jetty instance or an intermediate proxy that forwards raw HTTP/2 or HTTP/3 frames without validation.\n\nConsider a deployment utilizing an intermediate reverse proxy that routes requests based on the Host header, while Jetty serves virtual hosts based on the :authority pseudo-header. An attacker can set :authority: internal-admin.local and Host: public-site.com. The proxy permits the request because Host points to a public site, but Jetty receives the frame and processes it internally under the security context of the internal admin virtual host.\n\nFurthermore, if the application framework generates OAuth redirect URLs using Host header values while validating incoming sessions using the servlet API's target host, an attacker can hijack OAuth validation steps. This divergence allows redirection targets to point to attacker-controlled domains, resulting in session exposure or authorization bypasses.\n\nmermaid\ngraph LR\n Client[\"Client Request\"] -->|\":authority: internal-admin\"| JettyAPI[\"Jetty HttpURI State\"]\n Client -->|\"Host: public-site.com\"| AppLogic[\"Application/Proxy Headers\"]\n JettyAPI -->|\"Access Decisions (getServerName)\"| AuthZ[\"Authorized (Internal)\"]\n AppLogic -->|\"Redirects / DB Queries\"| AppRoute[\"Public Routing / Tenant Bypass\"]\n
The impact of this vulnerability depends on the topology of the target web environment and the specific APIs consumed by the backend application. Because the vulnerability results in host/authority desynchronization, it breaks security invariants that isolate tenants, control access, or structure fully qualified URLs.\n\nIn multi-tenant environments, virtual host isolation can be compromised if security checks are bound to the HttpURI context while downstream database querying uses the Host header. Additionally, web cache poisoning can occur if a caching reverse proxy hashes responses based on the Host header while the origin server returns content dynamically determined by the :authority pseudo-header.\n\nThe CVSS score is established at 5.3 (Medium), reflecting low-complexity network vectors with partial impact on integrity. However, in complex proxy-to-origin architectures, this mismatch can act as a primitive for escalating to high-severity access control bypasses.
Upgrading to patched releases of Jetty is the recommended path to resolve this vulnerability. The fix is backported across all active branches, including 9.x, 10.x, 11.x, and 12.x. These releases transition the compliance layer to fail-closed behavior for mismatched headers.\n\nIf immediate updates are unfeasible, administrators can implement a compliance listener to log mismatch attempts or enforce custom validation rules. The following listener registers violations and generates alerts when MISMATCHED_AUTHORITY occurs:\n\njava\nHttpConfiguration httpConfig = new HttpConfiguration();\nhttpConfig.addComplianceViolationListener(new ComplianceViolation.Listener() {\n @Override\n public void onComplianceViolation(ComplianceViolation.Event event) {\n if (event.violation() == HttpCompliance.Violation.MISMATCHED_AUTHORITY) {\n // Custom security log implementation\n logger.warn(\"Authority mismatch detected: \" + event.details());\n }\n } \n});\n\n\nAdditionally, edge proxies should be configured to strictly reject or normalize HTTP/2 and HTTP/3 requests where the :authority pseudo-header diverges from the Host header before passing traffic to Jetty backend servers.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Eclipse Jetty Eclipse Foundation | >= 9.4.0, < 9.4.61 | 9.4.61 |
Eclipse Jetty Eclipse Foundation | >= 10.0.0, < 10.0.29 | 10.0.29 |
Eclipse Jetty Eclipse Foundation | >= 11.0.0, < 11.0.29 | 11.0.29 |
Eclipse Jetty Eclipse Foundation | >= 12.0.0, < 12.0.35 | 12.0.35 |
Eclipse Jetty Eclipse Foundation | >= 12.1.0, < 12.1.9 | 12.1.9 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-20 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.3 (Medium) |
| Exploit Status | None (No public exploits) |
| CISA KEV Status | Not Listed |
| Impact | Integrity (Low) |
| Attack Complexity | Low (AC:L) |
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.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.