* caddytls: fix data race in session ticket key rotation
stayUpdated copies the map header (configs := s.configs) under the
lock, then iterates the original map after releasing it. Concurrent
calls to register/unregister mutate the same map.
Hold the lock for the entire iteration instead.
* caddytls: fix data race in AllMatchingCertificates
AllMatchingCertificates reads the package-level certCache without
acquiring certCacheMu, while Cleanup sets certCache to nil under
the write lock. The adjacent HasCertificateForSubject correctly
acquires certCacheMu.RLock.
Add the missing RLock/RUnlock to match.
* caddytls: fix ECH key rotation stopping permanently on error
When rotateECHKeys returns an error, the rotation goroutine returns
immediately, stopping all future key rotation for the lifetime of
the process.
Change return to continue, matching the error handling for
publishECHConfigs two lines below.
* caddytls: Fix wildcard race in auto-HTTPS launch
When evaluating whether to skip managing an individual subdomain
due to an existing wildcard configuration, we now explicitly consult
the automate loader.
Because Caddy apps can start in any order, relying strictly on the
TLS app's internal management state was non-deterministic if the
HTTP app started first. Checking the automate loader guarantees
predictable behavior since it is fully populated during the
Provision phase, well before any apps are started.
* respond to review comments
1. update requested comment
2. remove personal domain from test
3. add regression test
* remove unnecessary mutex lock
* refactor: -integration test, +explicit cases
* refactor: remove redundant test, add comment
* rename file and add header
* update copyright year
* tls: add alpn to managed HTTPS records
* tls: centralise HTTPS RR ALPN defaults and registration
Reuse shared protocol defaults instead of repeating the default HTTP protocol list, unify server name registration to carry ALPN in one experimental API and reuse the TLS default ALPN ordering for HTTPS RR publication
* http: centralise effective protocol resolution for HTTPS RR ALPN
Both fallbacks in splitPos relied on golang.org/x/text/search with
search.IgnoreCase, which performs Unicode equivalence matching far beyond
ASCII case folding. Combined with the validated-ASCII guarantee on every
SplitPath entry, that fallback turned non-PHP filenames into PHP scripts:
- when the inner loop hit a non-ASCII byte and the IndexString fallback
returned -1, the loop broke without resetting match=false, so a stale
match=true caused a non-existent .php to be reported (PoC:
"/name.<U+00A1>.txt").
- search.IgnoreCase folded fullwidth, mathematical and circled letters
onto ASCII, so "/shell.<math sans-serif php>",
"/shell.<fullwidth p>hp", "/shell.<circled php>" were all detected as
".php" files.
Replace the fallback with strict byte-level ASCII case-insensitive
matching: any byte >= utf8.RuneSelf in the path can never be part of a
match, since SplitPath entries are validated ASCII-only and lower-cased
in Provision(). This keeps the hot path branch-light and removes the
x/text/search dependency from the main module.
Reported against FrankenPHP as GHSA-3g8v-8r37-cgjm and
GHSA-v4h7-cj44-8fc8. The vulnerable function in this module was adapted
from the same FrankenPHP code.
* caddytls: Expand ACME credentials
This allows using global placeholders such as {file./run/secrets/key_id}
when setting up the tls configuration.
* chore(formatting): gofmt on acmeissuer_test
* reverseproxy: Add ability to clear dynamic upstreams cache during retries
This is an optional interface for dynamic upstream modules to implement if they cache results.
TODO: More documentation; this is an experiment.
* Add some godoc
* Export interface; update godoc
* admin: Redact sensitive request headers in API logs
* Fix govulncheck and typed atomic lint failures
* Sync Go module metadata after dependency downgrade
`reveal_symlinks` was exposing symlink targets as fully resolved absolute paths, even if the target is a relative path. With this change the link target is shown as-is, without resolving anything.
* feat: add system and combined CA pool modules
* fix: combining pools using `CertificateProvider`
* fix: lint issue
* chore: caddyfiletests
* doing it for first time, so not sure if its right.
* fix: use `x509` native addCert
* chore: explicit err handling
* Apply suggestion from @mohammed90
---------
Co-authored-by: Mohammed Al Sahaf <mohammed@caffeinatedwonders.com>
* add 'root' key to Helper.State for access in frankenphp's `php_server` directive
* clone state before passing it to child directives, but keep sharing it among sibling directives
* propagate named route state from children to parent
* use BlockState to set "root" instead
* gofmt -w .
* go fmt ./...
* here we go
Thank you for the report by @MaherAzzouzi, and the suggested fix!
2026-03-04 16:18:33 -07:00
Oleh Konko | semantic verification for trust infra | LLM-augmented operations pipeline (precision-first, claim≤evidence, submit-human) | verify the payload, not the signer
Only apply repl.ReplaceAll() on values from literal variable names
(e.g. map outputs), not on values resolved from placeholder keys
(e.g. {http.request.header.*}). The placeholder path already resolves
the value via repl.Get(), so a second expansion allows user-controlled
input containing {env.*} or {file.*} to be evaluated, leaking
environment variables and file contents.
Add regression test to verify placeholder-sourced values are not
re-expanded.
When using copy_headers in a forward_auth block, client-supplied headers with
the same names were not being removed before being forwarded to the backend.
This happens because PR #6608 added a MatchNot guard that skips the Set
operation when the auth service does not return a given header. That guard
prevents setting headers to empty strings, which is the correct behavior,
but it also means a client can send X-User-Id: admin in their request and
if the auth service validates the token without returning X-User-Id, Caddy
skips the Set and the client value passes through unchanged to the backend.
The fix adds an unconditional delete route for each copy_headers entry,
placed just before the existing conditional set route. The delete always runs
regardless of what the auth service returns. The conditional set still only
runs when the auth service provides that header.
The end result is:
- Client-supplied headers are always removed
- When the auth service returns the header, the backend gets that value
- When the auth service does not return the header, the backend sees nothing
Existing behavior is unchanged for any deployment where the auth service
returns all of the configured copy_headers entries.
Fixes GHSA-7r4p-vjf4-gxv4