On this page · 7 sections
- Caddy 2.11.9 Closes FastCGI Header, Path and Host Gaps
- Caddy 2.11.8 Tightens Host, Script, File and Proxy Handling
- Affected and Fixed Versions for Caddy FastCGI, Proxy and Path Fixes
- Also in this release
- Upgrade Steps for PHP, FastCGI and TLS Configurations
- Checking Caddyfiles for the Settings Named in the Notes
- Sources
Security advisory
Status as of 2026-11-08
CVE-2026-55458
Caddy: RFC 7230 §6.1 compliance issue / Hop-by-hop headers that leak through
- Affected
- < 2.11.5
- Fixed in
- 2.11.5
- Published
- 2026-11-05
Data: CVE record
Warning
Caddy 2.11.9 fixes FastCGI security issues, including GHSA-q34h-28rj-5hjm, in which a client could override HTTP_* variables set with the FastCGI transport's or php_fastcgi's env subdirective by sending a matching request header. The Caddy v2.11.9 release notes give no severity and no affected range for the GHSA items. The sources give a severity only for CVE-2026-55458: a CVSS 4.0 base score of 2.9 (LOW), assigned by GitHub_M, for caddyserver caddy < 2.11.5.
Caddy 2.11.9 Closes FastCGI Header, Path and Host Gaps #
The Caddy v2.11.9 release notes describe the release as a follow-up to 2.11.8 that fixes a regression and several security issues, mostly in FastCGI. They recommend upgrading if you are on 2.11.8 and serve PHP. The groups below follow the component each change touches: PHP environment values, script paths on Windows, HTTP/2 host handling and TLS policy merging.
Environment values for PHP applications #
A client could override any HTTP_* variable set with the env subdirective by sending a matching request header, such as the user an application sees in HTTP_X_AUTH_USER. GHSA-q34h-28rj-5hjm, reported by @JebeenLee and @Camel4 and fixed by @dunglas in #8358, makes the configured value win, so env values now take precedence over request headers. The same entry is listed under breaking changes, and the notes warn that these patches may break applications that rely on the buggy behavior.
"Configured values now win." (Caddy v2.11.9 release notes)
This suggests that a PHP application which read a client-supplied HTTP_X_AUTH_USER will now read the value set in the env block instead. Check any application that takes identity or routing data from HTTP_* variables, because the value it receives changes with this release.
Script selection with encoded slashes #
Encoded slashes and dot segments could make a path matcher that sees the escaped form approve one script while another ran. The notes give /public/tool.php%2f..%2f..%2fadmin%2ftool.php as an example. Under #8357, FastCGI requests whose escaped path and decoded path would select different scripts now get 400, and the notes list this as a breaking change.
Script paths on Windows #
On Windows, NTFS 8.3 short names and alternate data streams could run a script that a path rule was meant to deny (GHSA-9cr8-wmhh-39pm, #8356). Script paths with a short-name component such as ADMINI~1, or with a colon for an alternate data stream, now return 400. The notes present this as completing the FastCGI fix from 2.11.8.
HTTP/2 host values #
Over HTTP/2, a host field sent next to :authority could make the application see a different HTTP_HOST from the host Caddy routed the request to (#8355, @dunglas). The fix takes HTTP_HOST from the routed host only. This suggests that applications reading HTTP_HOST will now receive the routed host.
TLS policies shared by site blocks #
When two site blocks shared TLS connection policies for the same hostname but set different client_auth, the adapter kept the first and silently dropped the other, which could quietly remove a stricter mTLS requirement (#8306, credited to @sam-kota). The notes list this under 2.11.9 breaking changes, and conflicting client_auth is now a Caddyfile error. This suggests that such a configuration will fail to load until the conflict is removed.
Plugin maintainers and the go-jose update #
The release updates go-jose to v4.1.6 for GHSA-mgcc-cww5-fp2q (#8299). The notes warn that Dependabot will probably alert plugin maintainers and urge them to upgrade Caddy in go.mod. Maintainers should upgrade the Caddy dependency only if an exported API their plugin uses has changed.
Caddy 2.11.8 Tightens Host, Script, File and Proxy Handling #
The Caddy v2.11.8 release notes recommend upgrading especially if you serve PHP or use {host} in file paths. The notes say most of the breaking changes reject configs or requests that never did what they looked like they did. The groups below cover the security fixes and the breaking changes that affect those paths.
Hosts used in file paths #
A Host or :authority value with dot segments or slashes could escape the intended directory when used in a file path such as root /srv/sites/{host}, and with php_fastcgi it could execute files outside that directory (GHSA-r766-rf9f-588h, #8328, @dunglas). Requests with an invalid or dots-only host now get 400 on every protocol, before any route runs. The same change rejects HTTP/2 and HTTP/3 hosts containing / or \.
PHP script selection and php_fastcgi #
SCRIPT_FILENAME is now derived from the same normalized path that path matchers see, so a route guarded by a path matcher cannot be made to run a different script, as with /admin.php/../../other.php (GHSA-f278-mgc7-46j3, thanks @pamnario). The php_fastcgi rewrite always runs now. A php_fastcgi site without an index.php sends requests for missing paths to PHP as index.php instead of returning 404 from file_server (#8326).
PATH_INFO and DOCUMENT_URI are now derived from the normalized path, with repeated slashes merged and . segments removed, while REQUEST_URI is unchanged (#8326). The php_fastcgi trailing-slash redirect for directories with an index.php can no longer become an open redirect to another site (#8285, @sam-kota).
Static files, hidden data and rewrites #
The file matcher no longer resolves paths like /.env/./ to the regular file, which bypassed path rules such as path *.env (GHSA-25cw-38mq-q7m6, #8326). When neither HOME nor XDG_DATA_HOME is set, Caddy's data directory falls back to ./caddy, and a file_server serving the working directory could expose certificates and private keys; that directory is now always hidden (GHSA-jf74-f69g-hcj9, #8327).
Rewrites now escape {http.matchers.file.remainder} before rewriting, so double-encoded path info such as ..%252f cannot become ../ after path rules have run (GHSA-69hv-5jfc-mvmv, #8325). A try_files or file candidate ending in / only matches a directory, so /foo.txt/ no longer matches the file /foo.txt. Files excluded with hide no longer appear in browse listings, and hidden precompressed sidecars are no longer served (#8155, @agammann).
Reverse proxy hop-by-hop headers and CVE-2026-55458 #
The CVE record describes a reverse proxy path that handled an upstream 101 Switching Protocols response before the hop-by-hop header removal used for ordinary responses. It says an attacker who controls or compromises a proxied WebSocket upstream can cause Alt-Svc, Keep-Alive, Proxy-Authenticate and headers named by Connection to cross the proxy boundary. The record, published 2026-11-05 by GitHub_M, gives CWE-444 and a CVSS 4.0 base score of 2.9 (LOW), and states the issue is fixed in 2.11.5.
The 2.11.8 notes list stripping hop-by-hop headers from 1xx responses and from copy_response_headers in handle_response as completing the fix for CVE-2026-55458 (GHSA-8qx7-j2v2-x6q5, #8256, #8270, thanks @SssiiiSssii1 and @tomholford). So the fix for this CVE is split across releases: 2.11.5 is the version the record names, and 2.11.8 is the release whose notes describe the remaining header handling.
Query log filter #
The query log filter now parses request URIs the way the server does, so parameters after a # are redacted too (#8255, @jayhemnani9910).
Stricter request and config checks in 2.11.8 #
request_body max_size now rejects a request with 413 as soon as its Content-Length is over the limit, even if nothing would have read the body (#8337). encode now compresses responses even when the request has Cache-Control: no-transform, and responses that could have been encoded always get Vary: Accept-Encoding. To keep the old behavior, use @transformable not header Cache-Control *no-transform* and encode @transformable (#8301, #8025).
Several configs are now errors: more than one expression line in the same matcher set, which should be combined with && (#8183); unknown TLS curves or protocol_min / protocol_max names such as TLS1.3 instead of tls1.3 (#8266); a repeated sni_regexp in a TLS policy match block (#8137); ip_mask log filter sizes out of range, such as 33 for IPv4 (#8241); basic_auth usernames identical after placeholder expansion (#8315); and ports longer than 11 characters (#8277). Evaluation order for handle_errors blocks and for vars with non-path matchers now follows the Caddyfile, so a different block or value may win if codes overlap or a variable is set twice (#8195, #8197).
Affected and Fixed Versions for Caddy FastCGI, Proxy and Path Fixes #
| Change | Identifier | Affected | Fixed in |
|---|---|---|---|
| Request headers override FastCGI env values (#8358) | GHSA-q34h-28rj-5hjm | Not stated | 2.11.9 |
| Encoded slashes and dot segments in script paths (#8357) | None given | Not stated | 2.11.9 |
| Windows 8.3 short names and alternate data streams (#8356) | GHSA-9cr8-wmhh-39pm | Not stated | 2.11.9 |
| HTTP/2 host value sent with :authority (#8355) | None given | Not stated | 2.11.9 |
| Conflicting client_auth silently dropped (#8306) | None given | Not stated | 2.11.9 |
| go-jose dependency update (#8299) | GHSA-mgcc-cww5-fp2q | Not stated | 2.11.9 (go-jose v4.1.6) |
| PHP directory index regression (#8352) | None given | Regression introduced in 2.11.8 | 2.11.9 |
| Invalid or dots-only host, and hosts used in file paths (#8328) | GHSA-r766-rf9f-588h | Not stated | 2.11.8 |
| SCRIPT_FILENAME from normalized path | GHSA-f278-mgc7-46j3 | Not stated | 2.11.8 |
| File matcher with /.env/./ (#8326) | GHSA-25cw-38mq-q7m6 | Not stated | 2.11.8 |
| Data directory exposure when HOME and XDG_DATA_HOME are unset (#8327) | GHSA-jf74-f69g-hcj9 | Not stated | 2.11.8 |
| Rewrite remainder escaping (#8325) | GHSA-69hv-5jfc-mvmv | Not stated | 2.11.8 |
| Hop-by-hop headers in 1xx responses and copy_response_headers (#8256, #8270) | GHSA-8qx7-j2v2-x6q5; completes the fix for CVE-2026-55458 | Not stated | 2.11.8 |
| Hop-by-hop headers through a proxied WebSocket upstream | CVE-2026-55458 | caddyserver caddy < 2.11.5 | 2.11.5 (per the CVE record) |
Also in this release #
- 2.11.9: a try_files pattern matches a directory only when it ends in /, fixing a 2.11.8 regression where /wp-admin/ was matched by the directory and usually returned 404 (#8352, @dunglas).
- 2.11.9: path matchers with placeholders such as {env.FOO} are no longer lower-cased and compare case-insensitively against the request path (#8343, @BenMacha).
- 2.11.9: new plain_time_format option for file_server browse sets the time layout of plain-text listings (#8084, @steffenbusch).
- 2.11.9: httpcaddyfile.Helper.IsNamedRoute() tells a plugin directive whether it is parsed inside a named route (#8354).
- 2.11.9: fewer allocations in path cleaning, header rewriting and weighted_round_robin selection (#7842, @jvoisin); actions-deps group bump with 10 updates (#8340).
- 2.11.8: release builds use Go 1.27, and Go 1.26 is still the minimum to build Caddy (#8210).
- 2.11.8: idle timeout fixes, including per-route precedence over server-wide timeouts (#8121, #8125, #8145, #8284).
- 2.11.8: on Linux, Caddy raises CAP_NET_BIND_SERVICE only for binding a privileged port, so packagers can use setcap cap_net_bind_service=+p (#8102, #8253).
- 2.11.8: new log_level directive, such as log_level @healthchecks DEBUG (#8201), and new {time.now.rfc3339} placeholder (#8140).
- 2.11.8: new not matcher for TLS connection policies (#8138), and the tls matcher in CEL expressions (#8088).
- 2.11.8: ECH retry configs are sent when Caddy rejects Encrypted ClientHello (#8142), and client_auth modes request and verify_if_given no longer reject clients without a certificate (#8251).
- 2.11.8: reverse proxy keeps headers set by Caddy after a 1xx response (#8169), and dial errors through a forward proxy and to FastCGI backends are retried (#8264, #8172).
- The complete lists are in the Caddy v2.11.9 release notes and the Caddy v2.11.8 release notes.
Upgrade Steps for PHP, FastCGI and TLS Configurations #
- Before upgrading, search for site blocks that share a hostname and set different client_auth, because the conflict is now a Caddyfile error.
- If you are on 2.11.8 and serve PHP, upgrade to 2.11.9, as the release notes recommend. A version below 2.11.5 is listed as affected by CVE-2026-55458, and 2.11.9 is above that version.
- After upgrading, confirm that PHP applications read the env values you configured, since request headers no longer override them.
- After upgrading, check requests whose escaped path and decoded path select different scripts, such as %2f sequences, which now return 400.
- On Windows, check script paths that contain an 8.3 short name component or a colon, which now return 400.
- Plugin maintainers should upgrade the Caddy dependency only when an exported API they use has changed.
Checking Caddyfiles for the Settings Named in the Notes #
Run this search in the directory that holds your Caddyfile to list lines that use the settings these changes touch: client_auth for the TLS merge, env and php_fastcgi for header overrides, try_files for directory matching, and {host} for host-based paths. The pattern is a rough filter, so env also matches unrelated lines such as those containing the word environment.
grep -n -E "client_auth|env|php_fastcgi|try_files|\{host\}" CaddyfileSources
- Release v2.11.9 · caddyserver/caddy · GitHub github.com · Nov 5, 2026
- Release v2.11.8 · caddyserver/caddy · GitHub github.com · Nov 4, 2026
- CVE-2026-55458: Caddy: RFC 7230 §6.1 compliance issue / Hop-by-hop headers that leak through cve.org · Nov 5, 2026
Edited and approved by Jarosław Krzemiński. Spotted a mistake? Report a correction or read the corrections policy.




Comments