VersionDrift
Product

Caddy 2.11.7 → 2.11.8

1 release · 13 breaking changes · 9 security fixes · 5 advisories fixed

9security13breaking0deprecated18feature0fix

Vulnerabilities fixed by this upgrade

  • 5.9 GHSA-f278-mgc7-46j3 php_fastcgi authorization bypass via dot-segments in the request path
  • medium GHSA-jf74-f69g-hcj9 file_server exposes private keys when the data directory falls back to ./caddy
  • medium GHSA-69hv-5jfc-mvmv rewrite re-decodes {http.matchers.file.remainder}, bypassing path-based deny rules
  • medium GHSA-25cw-38mq-q7m6 file matcher resolves /file/./ to a regular file, bypassing suffix path rules
  • high GHSA-r766-rf9f-588h Host and :authority values with dot segments or slashes escape a {host}-based root

Breaking changes

  • breaking Requests with an invalid or dots-only host (like ..) are rejected with 400 on every protocol, before any route runs. Before, HTTP/2 and HTTP/3 also accepted hosts containing / or . (#8328) in 2.11.8
  • breaking 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) in 2.11.8
  • breaking php_fastcgi sites without an index.php: requests for paths that don't exist are now sent to PHP as index.php, as the documented first_exist_fallback try policy always promised, instead of falling through to file_server and returning 404. Also, PATH_INFO and DOCUMENT_URI are now derived from the… in 2.11.8
  • breaking A try_files / file candidate ending in / only matches a directory, so /foo.txt/ no longer matches the file /foo.txt. (#8326) in 2.11.8
  • breaking encode now compresses responses even when the request has Cache-Control: no-transform (a response's no-transform is still honored), and responses that could have been encoded always get Vary: Accept-Encoding. To keep the old behavior: @transformable not header Cache-Control no-transform and encode… in 2.11.8
  • breaking Stricter config validation. Some configs that were silently accepted (and didn't do what you'd expect) are now errors: in 2.11.8
  • breaking more than one expression line in the same matcher set (combine them with &&) (#8183) in 2.11.8
  • breaking unknown TLS curves or protocol_min / protocol_max names, like TLS1.3 instead of tls1.3, which used to be silently ignored (#8266) in 2.11.8
  • breaking a repeated sni_regexp in a TLS policy match block (#8137) in 2.11.8
  • breaking ip_mask log filter sizes out of range, like 33 for IPv4 (#8241) in 2.11.8
  • breaking basic_auth usernames that end up identical after placeholder expansion (#8315) in 2.11.8
  • breaking ports longer than 11 characters (#8277) in 2.11.8
  • breaking Evaluation order now follows the Caddyfile for handle_errors blocks with status codes and for vars with non-path matchers. If you had overlapping codes or set the same variable twice, a different block or value may now win. (#8195, #8197) in 2.11.8

Security changes

  • security caddyhttp: A Host / :authority value with dot segments or slashes could escape the intended directory when used in file paths, like root /srv/sites/{host}, and with php_fastcgi even execute files outside it. Such hosts are now rejected (see above). Thanks @dunglas. (GHSA-r766-rf9f-588h, #8328) in 2.11.8
  • security fastcgi: SCRIPT_FILENAME is now derived from the same normalized path that path matchers see, so a route protected by a path matcher can't be made to run a different script, e.g. with /admin.php/../../other.php. The php_fastcgi rewrite also always runs now (see above). Thanks @pamnario.… in 2.11.8
  • security fileserver: The file matcher no longer resolves paths like /.env/./ to the regular file, which bypassed path rules such as path *.env. Thanks @dunglas. (GHSA-25cw-38mq-q7m6, #8326) in 2.11.8
  • security rewrite: {http.matchers.file.remainder} is now escaped before rewriting, so double-encoded path info (like ..%252f) can't turn into ../ after path rules have run. Thanks @dunglas. (GHSA-69hv-5jfc-mvmv, #8325) in 2.11.8
  • security fileserver: 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. Thanks @dunglas. (GHSA-jf74-f69g-hcj9, #8327) in 2.11.8
  • security fastcgi: The php_fastcgi trailing-slash redirect for directories with an index.php can no longer be turned into an open redirect to another site. Thanks @sam-kota. (#8285) in 2.11.8
  • security fileserver: Files excluded with hide no longer show up in browse listings, and hidden precompressed sidecars are no longer served. Thanks @agammann. (#8155) in 2.11.8
  • security reverseproxy: Hop-by-hop headers are stripped from 1xx responses and from copy_response_headers in handle_response, completing the fix for CVE-2026-55458. Thanks @SssiiiSssii1 and @tomholford. (GHSA-8qx7-j2v2-x6q5, #8256, #8270) in 2.11.8
  • security logging: The query log filter now parses request URIs like the server does, so parameters after a # are redacted too. Thanks @jayhemnani9910. (#8255) in 2.11.8

Every release in between

featureIdle timeouts, round two. More fixes for the idle read/write timeouts introduced in 2.11.6:
featurePer-route timeouts now take precedence over the server-wide read_body_idle / write_idle, and nested timeouts use the innermost one. (#8121)
featureOver HTTP/2, a handler that paused reading the request body (like reverse_proxy uploading to a slow upstream) no longer loses the body and fails with 502. (#8125)
featureDeadlines set by handlers now act as a ceiling instead of being overridden, so things like Mercure's dispatch_timeout and FrankenPHP's request_body_timeout work again. Thanks @dunglas! (#8145, #8284)
featureHTTP/1.1 uploads that time out with a little body left no longer hang instead of sending the error response. Thanks @SiyXo511! (#8178)
featureBinding privileged ports with fewer capabilities (Linux): If CAP_NET_BIND_SERVICE is permitted but not effective, Caddy raises it just for binding a privileged port. Packagers can use setcap cap_net_bind_service=+p instead of +ep, so Caddy still starts under --cap-drop ALL, OpenShift's…
featurenew log_level directive to set the access log level for matching requests, e.g. log_level @healthchecks DEBUG (#8201)
featurenew {time.now.rfc3339} placeholder. Thanks @steadytao! (#8140)
featurenew not matcher for TLS connection policies. Thanks @simonether! (#8138)
featurethe tls matcher can be used in CEL expression matchers: tls(), tls('complete'), tls('early_data'). Thanks @stackedbyaradhya! (#8088)
featureheaders you set yourself (like Strict-Transport-Security via header) are no longer lost when the upstream sends a 1xx response first, like 103 Early Hints (#8169)
featurerequest trailer values are forwarded, not just their names. Thanks @krishsinghhura! (#8246)
featurerequest-only expressions in lb_retry_match no longer retry successful responses (a regression since 2.11.3) (#8168)
featuredial errors through a forward proxy and to FastCGI backends are retried like other dial errors. Thanks @adarshxsh and @zemamba! (#8264, #8172)
featureweighted_round_robin no longer panics with fewer weights than upstreams, and no longer picks an unavailable upstream when there's only one weight; random_choose picks the least loaded host when all are busy (#8159, #8320, #8160)
featurewith request_buffers / response_buffers unlimited, a body that fails partway is no longer treated as complete (#8207)
featureconnections and sockets are no longer leaked when a protocol upgrade (e.g. WebSocket) fails during setup, or when a handle_response status isn't a number. Thanks @Version2beta and @BenMacha! (#8269, #8318)
featureHTTP/3 client cancellations are logged at debug level instead of as warnings. Thanks @larrasket! (#8135)
breakingRequests with an invalid or dots-only host (like ..) are rejected with 400 on every protocol, before any route runs. Before, HTTP/2 and HTTP/3 also accepted hosts containing / or . (#8328)
breakingrequest_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)
breakingphp_fastcgi sites without an index.php: requests for paths that don't exist are now sent to PHP as index.php, as the documented first_exist_fallback try policy always promised, instead of falling through to file_server and returning 404. Also, PATH_INFO and DOCUMENT_URI are now derived from the…
breakingA try_files / file candidate ending in / only matches a directory, so /foo.txt/ no longer matches the file /foo.txt. (#8326)
breakingencode now compresses responses even when the request has Cache-Control: no-transform (a response's no-transform is still honored), and responses that could have been encoded always get Vary: Accept-Encoding. To keep the old behavior: @transformable not header Cache-Control no-transform and encode…
breakingStricter config validation. Some configs that were silently accepted (and didn't do what you'd expect) are now errors:
breakingmore than one expression line in the same matcher set (combine them with &&) (#8183)
breakingunknown TLS curves or protocol_min / protocol_max names, like TLS1.3 instead of tls1.3, which used to be silently ignored (#8266)
breakinga repeated sni_regexp in a TLS policy match block (#8137)
breakingip_mask log filter sizes out of range, like 33 for IPv4 (#8241)
breakingbasic_auth usernames that end up identical after placeholder expansion (#8315)
breakingports longer than 11 characters (#8277)
breakingEvaluation order now follows the Caddyfile for handle_errors blocks with status codes and for vars with non-path matchers. If you had overlapping codes or set the same variable twice, a different block or value may now win. (#8195, #8197)
securitycaddyhttp: A Host / :authority value with dot segments or slashes could escape the intended directory when used in file paths, like root /srv/sites/{host}, and with php_fastcgi even execute files outside it. Such hosts are now rejected (see above). Thanks @dunglas. (GHSA-r766-rf9f-588h, #8328)
securityfastcgi: SCRIPT_FILENAME is now derived from the same normalized path that path matchers see, so a route protected by a path matcher can't be made to run a different script, e.g. with /admin.php/../../other.php. The php_fastcgi rewrite also always runs now (see above). Thanks @pamnario.…
securityfileserver: The file matcher no longer resolves paths like /.env/./ to the regular file, which bypassed path rules such as path *.env. Thanks @dunglas. (GHSA-25cw-38mq-q7m6, #8326)
securityrewrite: {http.matchers.file.remainder} is now escaped before rewriting, so double-encoded path info (like ..%252f) can't turn into ../ after path rules have run. Thanks @dunglas. (GHSA-69hv-5jfc-mvmv, #8325)
securityfileserver: 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. Thanks @dunglas. (GHSA-jf74-f69g-hcj9, #8327)
securityfastcgi: The php_fastcgi trailing-slash redirect for directories with an index.php can no longer be turned into an open redirect to another site. Thanks @sam-kota. (#8285)
securityfileserver: Files excluded with hide no longer show up in browse listings, and hidden precompressed sidecars are no longer served. Thanks @agammann. (#8155)
securityreverseproxy: Hop-by-hop headers are stripped from 1xx responses and from copy_response_headers in handle_response, completing the fix for CVE-2026-55458. Thanks @SssiiiSssii1 and @tomholford. (GHSA-8qx7-j2v2-x6q5, #8256, #8270)
securitylogging: The query log filter now parses request URIs like the server does, so parameters after a # are redacted too. Thanks @jayhemnani9910. (#8255)
+109 more items in the release notes
See how far your stack has drifted from upstream. Release data from vendors’ own sources · feed under CC BY 4.0 · Code under AGPL-3.0 Settings Feed status