Skip to content

Commit

Permalink
caddyhttp: properly sanitize requests for root path
Browse files Browse the repository at this point in the history
SanitizePathJoin protects against directory traversal attacks by
checking for requests whose URL path look like they are trying to
request something other than a local file, and returns the root
directory in those cases.

The method is also careful to ensure that requests which contain a
trailing slash include a trailing slash in the returned value.  However,
for requests that contain only a slash (requests for the root path), the
IsLocal check returns early before the matching trailing slash is
re-added.

This change updates SanitizePathJoin to only perform the
filepath.IsLocal check if the cleaned request URL path is non-empty.

Fixes caddyserver#6352
  • Loading branch information
willnorris committed Jun 1, 2024
1 parent 40c582c commit 6b2979b
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 2 deletions.
2 changes: 1 addition & 1 deletion modules/caddyhttp/caddyhttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func SanitizedPathJoin(root, reqPath string) string {
}

relPath := path.Clean("/" + reqPath)[1:] // clean path and trim the leading /
if !filepath.IsLocal(relPath) {
if relPath != "" && !filepath.IsLocal(relPath) {
// path is unsafe (see https://github.com/golang/go/issues/56336#issuecomment-1416214885)
return root
}
Expand Down
10 changes: 9 additions & 1 deletion modules/caddyhttp/caddyhttp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ func TestSanitizedPathJoin(t *testing.T) {
inputPath: "/",
expect: ".",
},
{
// fileserver.MatchFile passes an inputPath of "//" for some try_files values.
// See https://github.com/caddyserver/caddy/issues/6352
inputPath: "//",
expect: "./",
},
{
inputPath: "/foo",
expect: "foo",
Expand Down Expand Up @@ -63,9 +69,11 @@ func TestSanitizedPathJoin(t *testing.T) {
expect: filepath.Join("/", "a", "b", "bar"),
},
{
// inputPath fails the IsLocal test so only the root is returned,
// but with a trailing slash since one was included in inputPath
inputRoot: "/a/b",
inputPath: "/%2e%2e%2f%2e%2e%2f",
expect: "/a/b", // inputPath fails the IsLocal test so only the root is returned
expect: "/a/b/",
},
{
inputRoot: "/a/b",
Expand Down

0 comments on commit 6b2979b

Please sign in to comment.