From 6deaa8e1a14d34d7c7d13daf32ef53174cc84610 Mon Sep 17 00:00:00 2001 From: "Nimer@Tornado" Date: Sun, 5 Jul 2026 05:04:38 +0300 Subject: [PATCH] fix: handle backslash-started paths in cleanPath MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves remaining Copilot review concern: paths starting with a bare backslash (e.g. \evil.com) were not caught by the previous guard and would be converted to /\evil.com by the 'missing root' logic, still enabling an open-redirect attack. Replace the two-part guard (loop for '//' + single-replace for '/\') with a unified loop that strips any leading run of '/' and '\' down to exactly one '/', covering: - //example.com → /example.com - /\example.com → /example.com - \example.com → /example.com - \\example.com → /example.com Add corresponding test cases. --- path.go | 19 +++++++++++++------ path_test.go | 6 ++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/path.go b/path.go index c079cb41..78fe2cec 100644 --- a/path.go +++ b/path.go @@ -25,12 +25,19 @@ func cleanPath(p string) string { if p == "" { return "/" } - // Prevent scheme-relative ("//...") or backslash-based absolute ("/\\...") paths. - for len(p) > 1 && p[0] == '/' && p[1] == '/' { - p = p[1:] - } - if len(p) > 1 && p[0] == '/' && p[1] == '\\' { - p = "/" + p[2:] + // Prevent scheme-relative or backslash-based absolute redirects by + // normalizing any leading run of '/' and '\' down to exactly one '/'. + if len(p) > 0 && (p[0] == '/' || p[0] == '\\') { + i := 0 + for i < len(p) && (p[i] == '/' || p[i] == '\\') { + i++ + } + if i == len(p) { + return "/" + } + if i > 1 || p[0] == '\\' { + p = "/" + p[i:] + } } // Reasonably sized buffer on stack to avoid allocations in the common case. diff --git a/path_test.go b/path_test.go index eba1be08..0f1f9235 100644 --- a/path_test.go +++ b/path_test.go @@ -42,6 +42,12 @@ var cleanTests = []cleanPathTest{ {"///abc", "/abc"}, {"//abc//", "/abc/"}, + // Prevent scheme-relative and backslash-based open redirect (security) + {"/\\evil.com", "/evil.com"}, + {"\\evil.com", "/evil.com"}, + {"\\\\evil.com", "/evil.com"}, + {"/\\/evil.com", "/evil.com"}, + // Remove . elements {".", "/"}, {"./", "/"},