fix(workspaces): key basic-auth bypass on resolved client IP - #10
Merged
Merged
Conversation
- all proxied traffic has a private-range tcp peer (coolify proxy), so the remote_ip-based private-peer exemption disabled auth for everyone - resolve the client ip via caddy client_ip through trusted_proxies: public-range forwarded clients authenticate, in-network peers and the loopback health probe stay exempt - public-range peer spoofed headers ignored (untrusted); forgery from a trusted peer can only require more auth, never grant a bypass - verify matrix gains the missing proxied-public-client case plus private-client bypass and trusted-peer header resolution assertions - align auth contract docs across repo
This comment has been minimized.
This comment has been minimized.
pcfreak30
marked this pull request as ready for review
September 24, 2026 23:09
- trusted_proxies_strict parses the XFF chain right-to-left (first untrusted address); the default left-to-right scan lets a proxied client spoof a private-range leftmost entry (e.g. X-Forwarded-For: 127.0.0.1) and resolve client_ip to it, bypassing auth internet-wide - strict mode is available since Caddy v2.8; this image pins 2.11.4 - verify matrix gains the chained-XFF case (spoofed private prefix + public client -> 401) and an all-private-chain fallback case - align bypass-resolution comments/docs to strict semantics
Kody Review CompleteGreat news! 🎉 Keep up the excellent work! 🚀 Kody Guide: Usage and ConfigurationInteracting with Kody
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
All workspace traffic arrives through the Coolify proxy, whose TCP peer is a private-range address, so the private-peer exemption matched every request and
basicauthnever fired — auth was silently off for the whole internet.Switches the bypass to Caddy's
client_ipmatcher throughtrusted_proxies private_ranges: proxied public-range clients require credentials, in-network peers (Cast's anonymous probe) and the localhost/healthzcheck stay exempt, and a public-range peer's forgedX-Forwarded-Forstays ignored as an untrusted peer. Documents the assumption that the deployment proxy always setsX-Forwarded-For(Traefik/Caddy default).Adds the missing verification case — a private-range peer forwarding a public-range client — plus credential-matrix and private-client-bypass assertions, and aligns the auth-contract docs.
fix(workspaces): key basic-auth bypass on resolved client IP
Summary
Fixes a critical HTTP Basic Auth bypass in the workspace runtime image (
images/php-caddy/Caddyfile). The auth exemption previously keyed on Caddy'sremote_ipmatcher (the raw TCP peer). In production, every request reaches the container through the private-range Coolify proxy, so a peer-based exemption meant all proxied traffic — including every public internet client — bypassed authentication, silently disabling auth.What changed
images/php-caddy/Caddyfile: The Basic Auth exemption matcher was switched fromremote_iptoclient_ip. Through the already-configuredtrusted_proxies static private_ranges, Caddy now resolves the real client IP from the trusted private-range proxy'sX-Forwarded-For(or uses the raw peer when no forwarded chain exists):401without them./healthzand in-deployment probes (e.g. Cast's anonymous export probe) stay unauthenticated.X-Forwarded-For/X-Real-IPheaders are ignored and auth is enforced against their real peer address.scripts/verify-php-caddy.sh: Added regression tests for the production topology:X-Forwarded-For: 192.0.2.77) →401without credentials,200with valid credentials,401with bad credentials;200without credentials (stays exempt);401(previously expected200);200;401.Documentation (
AGENTS.md,README.md,images/php-caddy/README.md,images/wordpress/README.md): Updated the auth-contract docs to describe the resolved-client-IP model, the trust assumptions (private-range peers trusted, public peers untrusted), and why a peer-IP-based (remote_ip) bypass is unsafe (it would exempt the private-range proxy peer and disable auth for the whole internet).Review finding
The automated review reported 1 critical finding: the Caddy
client_ipresolution is flagged as parsingX-Forwarded-Fornon-strictly (left→right), which could allow a public attacker forging a loopback XFF header to bypass Basic Auth via the trusted proxy. This remains recorded as a known risk to follow up on.