From b51b4ad16ba3002a8f535a30aef155f9e0d34281 Mon Sep 17 00:00:00 2001 From: alhudz Date: Thu, 18 Jun 2026 19:23:02 +0530 Subject: [PATCH] fix escaped path matcher over-matching longer paths --- modules/caddyhttp/matchers.go | 14 ++++++++++++++ modules/caddyhttp/matchers_test.go | 15 +++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index 9f84a90da0d..8bd18ba4835 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -640,6 +640,20 @@ func (MatchPath) matchPatternWithEscapeSequence(escapedPath, matchPath string) b iPattern++ } + // if the pattern was fully consumed before the path, the remaining path + // bytes still have to be part of the string we match against; otherwise a + // pattern with no trailing wildcard (e.g. "/foo%2fbar") would behave like a + // prefix match and incorrectly match longer paths (e.g. "/foo%2fbarbaz"). + // the pattern has no more escape hints here, so compare in normalised space. + if iPath < len(escapedPath) { + remaining := escapedPath[iPath:] + if unescaped, err := url.PathUnescape(remaining); err == nil { + sb.WriteString(unescaped) + } else { + sb.WriteString(remaining) + } + } + // we can now treat rawpath globs (%*) as regular globs (*) matchPath = strings.ReplaceAll(matchPath, "%*", "*") diff --git a/modules/caddyhttp/matchers_test.go b/modules/caddyhttp/matchers_test.go index c0f02d23c58..e256f76b0d7 100644 --- a/modules/caddyhttp/matchers_test.go +++ b/modules/caddyhttp/matchers_test.go @@ -422,6 +422,21 @@ func TestPathMatcher(t *testing.T) { input: "/ADMIN%2fPaAzZLm123NEL", expect: true, }, + { + match: MatchPath{"/foo%2fbar"}, + input: "/foo%2fbarbaz", + expect: false, + }, + { + match: MatchPath{"/foo%2f"}, + input: "/foo%2fx", + expect: false, + }, + { + match: MatchPath{"/admin%2fpanel"}, + input: "/admin%2fpanelX", + expect: false, + }, } { err := tc.match.Provision(caddy.Context{}) if err == nil && tc.provisionErr {