Jul 23, 2026·7 min read·98 visits
Eclipse Jetty suffers from a path traversal vulnerability where state desynchronization in the URI parsing code allows unnormalized paths containing directory traversal sequences (such as '/public;/../admin') to be forwarded to downstream security components, leading to authentication and authorization bypasses.
A path traversal vulnerability exists in Eclipse Jetty due to a state-desynchronization defect in the URI parsing state machine inside URIUtil.java. This defect allows unauthenticated remote attackers to bypass path-based security constraints enforced by downstream filters, application gateways, or authorization modules by crafting URIs with path parameter delimiters and parent directory traversal sequences.
Eclipse Jetty processes HTTP request URIs to canonicalize resource locations and determine access controls. A path-traversal vulnerability, tracked as CVE-2026-8384, resides within the URI parser component in org.eclipse.jetty.util.URIUtil. When a request URI contains path parameters delimited by semicolons (;) adjacent to relative path traversal segments (..), the parser fails to identify and resolve these traversal segments.
Because the internal state machine tracking directory boundaries becomes desynchronized during parser execution, the canonicalization process skips the normalization step. Consequently, unresolved paths containing raw relative path elements are handed over to the servlet API and downstream web applications.
While Jetty's internal static resource alias checker prevents direct local file exposure from its resource handlers, the vulnerability exposes critical attack surface in multi-tier applications. Downstream components, such as Spring Security, reverse proxies, and servlet filters, rely on Jetty's canonicalization output to enforce authorization policies. If these filters evaluate the unnormalized path, an attacker can bypass pattern-matching rules and access restricted application context handlers.
The root cause of this vulnerability lies in the parser state tracking within URIUtil.canonicalPath() and URIUtil.decodePath(). During tokenization, the parser utilizes a boolean flag named slash to record whether the previously processed character was a forward slash (/). This flag is critical because the parser determines if a sequence of dot characters represents a relative path traversal sequence (. or ..) based on whether it is preceded by a directory separator.
When a semicolon (;) is processed inside the main state switch block, the parser enters a nested while loop designed to skip the path parameters until the next path boundary is reached. The nested loop increments the string index pointer i and searches for the next forward slash character, successfully advancing past the parameter content. Once it locates a slash, it appends it to the path builder block and exits the nested loop.
However, the parser fails to update the local loop-control variable c with the newly encountered slash character inside this nested sub-loop. When control returns to the main loop, a trailing state assignment is executed: slash = (c == '/'). Because the variable c still stores the stale semicolon character, the slash flag is incorrectly set to false, even though a slash character was just written to the path output.
On the next iteration of the main loop, the parser processes the dot characters (.). Because the slash flag is false, the parser assumes the dot is part of a standard filename rather than a structural traversal element. It bypasses the safety assignment normal = false, leaving the state variable normal marked as true. This prevents the parser from calling normalizePath(), leaving the .. segments unresolved in the final output stream.
The vulnerability is resolved by ensuring the state variable c is updated inside all nested parameter-skipping loops before the parser exits them. This synchronizes the loop control variable with the structural state.
Below is a comparison of the parser logic in URIUtil.java before and after the application of the official security patch:
// Vulnerable Code Path (Prior to Fix)
while (++i < end)
{
// The index is advanced and slash is checked
if (encodedPath.charAt(i) == '/')
{
builder.append('/');
break; // Exits loop while 'c' remains set to ';'
}
}
// Trailing state assignment updates with stale 'c'
slash = (c == '/'); // Evaluates to false// Patched Code Path (Post-Fix)
while (++i < end)
{
// Synchronize the current state variable 'c' with the active character pointer
c = encodedPath.charAt(i);
if (c == '/')
{
builder.append('/');
break; // Exits loop with 'c' correctly representing '/'
}
}
// Trailing state assignment updates with correct 'c'
slash = (c == '/'); // Evaluates to trueThe implementation of c = encodedPath.charAt(i) ensures that when a directory boundary slash is consumed to terminate the matrix-skipping loop, the character state tracks the transition. Consequently, when the main parsing loop resumes, the subsequent dots are correctly identified as directory traversal operators.
Exploitation of CVE-2026-8384 depends on a specific layout of security layers upstream from the Jetty servlet context. An attacker target must feature a gateway, reverse proxy, or servlet filter that performs pattern-matching on the request URI to restrict access to privileged administrative paths (e.g., /admin/*).
To perform the bypass, the attacker initiates an HTTP request targeting a public endpoint, appends a semicolon path-parameter delimiter, and immediately appends path traversal sequences pointing to the restricted path.
GET /public;/../admin/secret.txt HTTP/1.1
Host: vulnerable-application.local
Connection: closeWhen the security module (such as a pattern-matching filter or custom security gateway) evaluates the request URI, it receives /public/../admin/secret.txt directly from the container's unnormalized path state. If the security module checks for explicit matches like /admin/*, the validation is bypassed because the prefix is evaluated as /public/.
Once the security validation passes, the request is dispatched to the target application context. The downstream servlet dispatcher or system context resolves the relative path on the target filesystem or mapping context, translating /public/../admin/secret.txt to the restricted destination /admin/secret.txt, resulting in unauthorized access.
The CVSS v3.1 base score is 5.3 (Medium). This severity rating reflects the constraint that Jetty's default static file handler itself does not serve arbitrary filesystem resources via this vector due to alias checking controls. Therefore, Confidentiality and Availability are scored as None (C:N/A:N) in isolated, generic environments.
However, the real-world impact in enterprise enterprise-grade microservices is often High. Because Jetty acts as a primary application servlet engine for massive web ecosystems, the parsing desynchronization results in complete authentication and authorization bypasses on custom downstream filters. When path-based access control is neutralized, unauthenticated remote attackers can gain full read and write access to administrative actions and databases exposed through internal servlet mappings.
According to EPSS data, the active exploitation probability remains low, but security administrators must treat any custom application stack running affected versions of Jetty with high priority due to the ease of exploitation.
The primary recommendation is to update Eclipse Jetty to a non-vulnerable release branch. If upgrading Jetty is not immediately feasible, deploy immediate structural workarounds.
Configure front-end proxies, load balancers, or API Gateways (such as NGINX, HAProxy, or Envoy) to strictly normalize URIs prior to routing requests to the Jetty backend. Ensure that the proxy is configured to strip or block matrix parameters containing semicolons (%3b or ;) from paths, or reject requests matching traversal vectors.
Security operations teams should monitor incoming web server access logs and Web Application Firewall (WAF) logs for URI patterns matching semicolon delimiters followed by relative traversal patterns.
# Example WAF / Snort pattern logic
(?i);\/.*?\/\.\.\/This pattern flags instances where matrix segments are chained with back-to-back path transitions, which is a signature of exploitation attempts targeting this parsing flaw.
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 | >= 12.0.0, <= 12.0.34 | 12.0.35 |
Eclipse Jetty Eclipse Foundation | >= 12.1.0, <= 12.1.8 | 12.1.9 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-647 (Improper Neutralization of Sanitization-Related Special Elements) |
| Attack Vector | Network |
| CVSS v3.1 Score | 5.3 (Medium) |
| EPSS Score | 0.00198 |
| Exploit Status | poc |
| CISA KEV Status | Not Listed |
The product receives input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that are used to denote boundaries or structure when the input is sent to a downstream component.
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.