Skip to content

[12.0.x] Reuses URIUtil.canonicalPath() for URI matching. - #15615

Merged
sbordet merged 1 commit into
jetty-12.0.xfrom
fix/jetty-12.0.x/httpclient-canonical-match
Aug 24, 2026
Merged

sbordet merged 1 commit into
jetty-12.0.xfrom
fix/jetty-12.0.x/httpclient-canonical-match

Conversation

@sbordet

@sbordet sbordet commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

12.0.x backport of #15612

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
@sbordet
sbordet requested a review from lorban August 19, 2026 09:35
@sbordet sbordet self-assigned this Aug 19, 2026
@sbordet sbordet moved this to 👀 In review in FROZEN Jetty 12.0.39 Aug 19, 2026
@sbordet
sbordet merged commit 10b4bb1 into jetty-12.0.x Aug 24, 2026
9 checks passed
@github-project-automation github-project-automation Bot moved this from 👀 In review to ✅ Done in FROZEN Jetty 12.0.39 Aug 24, 2026
@sbordet
sbordet deleted the fix/jetty-12.0.x/httpclient-canonical-match branch August 24, 2026 06:28
@github-actions

Copy link
Copy Markdown

Hi @sbordet, this PR was merged without any labels. Please add at least one label (e.g., Bug, Enhancement, Documentation).

@sbordet sbordet added the Bug For general bugs on Jetty side label Aug 29, 2026
pstreef added a commit to moderne-backpatch-alliance/backpatch-jetty.project that referenced this pull request Oct 29, 2026
…ment boundary

GHSA-j5fg-j6xp-mjwf. AbstractAuthentication.matchesURI compared the
decoded request path with String.startsWith, so credentials registered for
http://host/secure were also sent to /secure/../evil, to /secure2 and to
any path that only shares the prefix. HttpRedirector takes a redirect to an
absolute path such as /secure/../evil as it is (URI.resolve does not
normalise an absolute path), so a redirect carried the Authorization
header there.

As upstream, both paths are now canonical before the comparison, and the
registered path must end at a segment boundary of the requested one. A
null scheme or host no longer throws.

Adapted from upstream's 12.0.x fix (PR jetty#15615):
- a7c18a8 (Simone Bordet):
  Reuses URIUtil.canonicalPath() for URI matching
from https://github.com/eclipse/jetty.project. Jetty 12's
URIUtil.canonicalPath(rawPath) does not exist in 9.4, so a private
canonicalPath in AbstractAuthentication stands in for it: it strips path
parameters, decodes the encoded ASCII characters of upstream's safe set
(RFC 3986 unreserved plus ! $ & ' ( ) * + , : = @), keeps other encodings in
upper case so %2F stays apart from '/', and removes dot segments with 9.4's
URIUtil.canonicalPath (null above the root). Unlike upstream it does not
decode non-ASCII UTF-8, so a non-ASCII character percent-encoded on one side
and literal on the other no longer matches (stricter, never broader; Peter,
2026-10-29: "b sounds closer to upstream, do that"). Every case
of upstream's test gives upstream's answer.

Tests: upstream's HttpAuthenticationStoreTest#testFindAuthenticationWithURI
(31 cases), its text block written as a CsvSource array for Java 8;
ours, #testFindAuthenticationWithEncodedSafeCharacters: encoded and literal
safe ASCII characters match, an encoded dot segment does not escape the
registered path, and encoded vs literal non-ASCII does not match.

Upstream-Commit: a7c18a8
Upstream-Commit: 10b4bb1
Co-authored-by: Simone Bordet <simone.bordet@gmail.com>
pstreef added a commit to finos-osera-forks/patch-jetty.project that referenced this pull request Oct 29, 2026
…ment boundary

GHSA-j5fg-j6xp-mjwf. AbstractAuthentication.matchesURI compared the
decoded request path with String.startsWith, so credentials registered for
http://host/secure were also sent to /secure/../evil, to /secure2 and to
any path that only shares the prefix. HttpRedirector takes a redirect to an
absolute path such as /secure/../evil as it is (URI.resolve does not
normalise an absolute path), so a redirect carried the Authorization
header there.

As upstream, both paths are now canonical before the comparison, and the
registered path must end at a segment boundary of the requested one. A
null scheme or host no longer throws.

Adapted from upstream's 12.0.x fix (PR jetty#15615):
- a7c18a8 (Simone Bordet):
  Reuses URIUtil.canonicalPath() for URI matching
from https://github.com/eclipse/jetty.project. Jetty 12's
URIUtil.canonicalPath(rawPath) does not exist in 9.4, so a private
canonicalPath in AbstractAuthentication stands in for it: it strips path
parameters, decodes the encoded ASCII characters of upstream's safe set
(RFC 3986 unreserved plus ! $ & ' ( ) * + , : = @), keeps other encodings in
upper case so %2F stays apart from '/', and removes dot segments with 9.4's
URIUtil.canonicalPath (null above the root). Unlike upstream it does not
decode non-ASCII UTF-8, so a non-ASCII character percent-encoded on one side
and literal on the other no longer matches (stricter, never broader; Peter,
2026-10-29: "b sounds closer to upstream, do that"). Every case
of upstream's test gives upstream's answer.

Tests: upstream's HttpAuthenticationStoreTest#testFindAuthenticationWithURI
(31 cases), its text block written as a CsvSource array for Java 8;
ours, #testFindAuthenticationWithEncodedSafeCharacters: encoded and literal
safe ASCII characters match, an encoded dot segment does not escape the
registered path, and encoded vs literal non-ASCII does not match.

Upstream-Commit: a7c18a8
Upstream-Commit: 10b4bb1
Co-authored-by: Simone Bordet <simone.bordet@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug For general bugs on Jetty side

Projects

No open projects
Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

2 participants