CVE-2026-8384: Path Traversal

Published Jul 14, 2026
·
Updated

Description (as reported)

Summary

In Jetty 12.1.8, org.eclipse.jetty.util.URIUtil.canonicalPath() may leave dot-dot path segments unnormalized when a semicolon path parameter marker is followed by a slash and a dot segment.

A minimal example is:

/public;/../admin/secret

In my local reproduction, URIUtil.canonicalPath() returns:

/public/../admin/secret

instead of the expected normalized path:

/admin/secret

When Jetty's SecurityHandler.PathMapped is used to protect a path prefix such as /admin/, the non-normalized canonical path may not match the protected prefix. As a result, an unauthenticated request may bypass the configured path-based security constraint.

Tested Version

Jetty: 12.1.8 JDK: 17.0.18 Maven: 3.9.14

Maven artifacts used:

org.eclipse.jetty:jetty-server:12.1.8 org.eclipse.jetty:jetty-security:12.1.8 org.eclipse.jetty:jetty-session:12.1.8

Only confirmed Jetty 12.1.8 so far.

Minimal Reproduction

Starts a minimal Jetty server with the following security setup:

java SecurityHandler.PathMapped security = new SecurityHandler.PathMapped(); security.put("/admin/", Constraint.from("admin")); security.put("/", Constraint.ALLOWED); security.setAuthenticator(new BasicAuthenticator());

The test then sends requests with no Authorization header.

Observed result:

GET /admin/secret -> 401 GET /public;x/../admin/secret -> 200

The handler receives paths such as:

/public/../admin/secret

This suggests that the /admin/ security constraint is bypassed because PathMapped matching is performed against the non-normalized canonical path.

Suspected Root Cause

The suspected root cause is in URIUtil.canonicalPath().

The relevant logic is approximately:

java for (int i = 0; i < end; i++) { char c = encodedPath.charAt(i);

switch (c) { case ';': if (builder == null) { builder = new Utf8StringBuilder(encodedPath.length()); builder.append(encodedPath, 0, i); }

while (++i < end) { if (encodedPath.charAt(i) == '/') { builder.append('/'); break; } } break;

case '.': if (slash) normal = false; if (builder != null) builder.append(c); break; }

slash = c == '/'; }

String canonical = (builder != null) ? (onBadUtf8 == null ? builder.toCompleteString() : builder.takeCompleteString(onBadUtf8)) : encodedPath; return normal ? canonical : normalizePath(canonical);

For the input:

/public;/../admin/secret

when the outer loop reaches the semicolon:

i = 7 c = ';' slash = false normal = true

Inside case ';', the while (++i < end) loop advances i to the next character, which is already '/' for the empty path parameter form ";/".

The code then appends '/' to the canonical builder:

builder.append('/');

At this point, the canonical builder ends with '/':

/public/

However, the local variable c is still the old value ';', because c was read before entering the switch and is not updated when the inner loop advances i.

After leaving the switch, the loop updates the slash state using:

slash = c == '/';

Since c is still ';', slash becomes false.

On the next iteration, the scanner reaches '.', which is the first dot in the following "../" segment. Because slash is incorrectly false, this code does not run:

java if (slash) normal = false;

Therefore normal remains true, and canonicalPath() returns the canonical string directly instead of calling normalizePath(canonical).

The result is:

/public/../admin/secret

instead of:

/admin/secret

In short:

case ';' advances the scan position i and appends '/' to the canonical builder, but the loop tail still updates slash from the stale character c=';'. As a result, the following dot-dot segment is not detected as a path traversal segment.

More Precise Trigger Condition

The issue is not limited to a non-empty path parameter such as ";x".

The more precise trigger shape is:

;[^/]/.

Examples:

/public;/../admin/secret /public;x/../admin/secret /public;anything/../admin/secret /public;/./admin/secret

The minimal form is:

/public;/../admin/secret

because the semicolon is immediately followed by '/', so the inner while loop reaches '/' on its first increment.

Potential Minimal Fix Direction

A minimal fix would be to ensure that, when case ';' consumes input until '/' and appends '/' to the canonical builder, the slash state reflects the last effective character in the canonical path.

For example, conceptually:

java case ';': if (builder == null) { builder = new Utf8StringBuilder(encodedPath.length()); builder.append(encodedPath, 0, i); }

while (++i < end) { if (encodedPath.charAt(i) == '/') { builder.append('/'); slash = true; break; } } continue;

The important part is to avoid the loop tail from overwriting slash using the stale c value:

slash = c == '/';

In other words, slash should represent the last effective character appended to the canonical builder, not the original input character read before case ';' advanced i.

Other sources

In Eclipse Jetty, an HTTP URI of this form:

/public;/../admin/secret.txt

results in an unresolved path of:

/public/../admin/secret.txt

instead of the expected:

/admin/secret.txt

Jetty itself is not affected, as it will not serve the secret.txt file because it will not pass the alias checker (only resolved resources are served).

However, web applications that rely on resolved paths being provided by Jetty may be confused when receiving an unresolved path.

NVD

Affected Software

5 affected componentsFixes available
Eclipse Jetty
Eclipse Jetty>=12.0.0<12.0.35
Eclipse Jetty>=12.1.0<12.1.9
maven/org.eclipse.jetty:jetty-util>=12.1.0<=12.1.8
12.1.9
maven/org.eclipse.jetty:jetty-util>=12.0.0<=12.0.34
12.0.35

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade maven/org.eclipse.jetty:jetty-util to a version that resolves this vulnerability.

    Fixed in 12.1.9
  2. Upgrade

    Upgrade maven/org.eclipse.jetty:jetty-util to a version that resolves this vulnerability.

    Fixed in 12.0.35

Event History

Jul 14, 2026
CVE Published
via MITRE·08:56 AM
Data Sourced
via MITRE·08:56 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·09:16 AM
DescriptionSeverityWeaknessAffected Software
Jul 22, 2026
Advisory Published
via GitHub·10:57 PM
Data Sourced
via GitHub·10:57 PM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-8384?

The severity of CVE-2026-8384 is rated as medium with a score of 5.3.

2

How does CVE-2026-8384 affect Eclipse Jetty?

CVE-2026-8384 can lead to unresolved path issues when accessing certain URIs, though Jetty itself does not serve affected files.

3

What is the risk associated with CVE-2026-8384?

CVE-2026-8384 has an associated risk score of 27, indicating a moderate level of concern.

4

How do I mitigate the effects of CVE-2026-8384?

To mitigate CVE-2026-8384, ensure proper URI handling and restrict access to sensitive files in your Eclipse Jetty configuration.

5

When was CVE-2026-8384 published?

CVE-2026-8384 was published on July 14, 2026.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203