Skip to content

fileserver: map invalid path errors to fs.ErrInvalid, and return 400 â€Ķ - #7017

Merged
mholt merged 1 commit into
caddyserver:masterfrom
Compy:bugfix-7008-fs-handle-invalid-paths
May 13, 2025
Merged

mholt merged 1 commit into
caddyserver:masterfrom
Compy:bugfix-7008-fs-handle-invalid-paths

Conversation

@Compy

@Compy Compy commented May 13, 2025 •

Copy link
Copy Markdown
Contributor

â€Ķfor any invalid path errors. (close #7008 #7007)

Background
Currently when using the static file server, when injecting a null byte into the request path, the server returns a 500. Edge infrastructure such as nginx, Apache, AWS ELB and Cloudflare treat these types of errors with a 400 Bad Request, which is more indicative of a bad input compared to an application-level 500 response.

This change adds error handling for fs.PathError to the mapDirOpenError() function by mapping it to fs.ErrInvalid, and modifies the caller (ServeHTTP()) to explicitly return http.StatusBadRequest for fs.ErrInvalid errors.

Local tests are positive. Unit tests are also passing. Tested on both MacOS and Linux/Ubuntu 24.

Before the change:

curl http://localhost:8080/foo.txt%00 -vvvv
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /foo.txt%00 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 500 Internal Server Error
< Server: Caddy
< Date: Tue, 13 May 2025 02:52:15 GMT
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

After the change:

curl http://localhost:8080/foo.txt%00 -vvvv
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8080...
* Connected to localhost (::1) port 8080
> GET /foo.txt%00 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 400 Bad Request
< Server: Caddy
< Date: Tue, 13 May 2025 02:54:16 GMT
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

@mholt mholt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks, this is pretty simple. Looks like a good patch.

@mholt
mholt merged commit 94147ca into caddyserver:master May 13, 2025
@mholt mholt added this to the v2.10.1 milestone May 13, 2025
@BrewTestBot BrewTestBot mentioned this pull request Aug 22, 2025
1 task done
mohammed90 pushed a commit to cedricziel/caddy that referenced this pull request Aug 29, 2025
@mholt

mholt commented Nov 10, 2025

Copy link
Copy Markdown
Member

@Compy Could you take a look at this change relative to this report: https://caddy.community/t/nextcloud-setup-broken-after-update-to-2-10-2/33140

It might be that we are applying this error a bit too generously... (or, maybe we are just now returning an error where before a bug was being covered up?)

klokv added a commit to klokv/caddy that referenced this pull request Oct 2, 2026
Since caddyserver#7017, every *fs.PathError from stat became fs.ErrInvalid before
the non-directory walk in mapDirOpenError could run. ENOTDIR is a path
error too, so a request like /index.php/foo got 400 instead of 404, and
pass_thru no longer fell through to the next handler.

Run the walk first so a regular-file parent is reported as not found,
then map the remaining path errors to fs.ErrInvalid as caddyserver#7017 intended.
klokv added a commit to klokv/caddy that referenced this pull request Oct 3, 2026
Since caddyserver#7017, every *fs.PathError from stat becomes fs.ErrInvalid, and
that includes ENOTDIR. So a request like /index.php/foo got 400 instead
of 404, and pass_thru no longer fell through to the next handler.

Map ENOTDIR to fs.ErrNotExist before that check. Other path errors, such
as NUL bytes, overly long names, or transient I/O failures, keep their
current handling.
klokv added a commit to klokv/caddy that referenced this pull request Oct 3, 2026
Since caddyserver#7017, every *fs.PathError from stat becomes fs.ErrInvalid, and
that includes ENOTDIR. So a request like /index.php/foo got 400 instead
of 404, and pass_thru no longer fell through to the next handler.

Map ENOTDIR to fs.ErrNotExist before that check. Other path errors, such
as NUL bytes, overly long names, or transient I/O failures, keep their
current handling.
steadytao pushed a commit that referenced this pull request Oct 4, 2026
Since #7017, every *fs.PathError from stat becomes fs.ErrInvalid, and
that includes ENOTDIR. So a request like /index.php/foo got 400 instead
of 404, and pass_thru no longer fell through to the next handler.

Map ENOTDIR to fs.ErrNotExist before that check. Other path errors, such
as NUL bytes, overly long names, or transient I/O failures, keep their
current handling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

500 Internal Server Error for URL Containing Null Byte (%00)

2 participants