
CakePHP 5.4.2 - High - Remote - Proxy - trustedProxies honors X-Forwarded-* from any REMOTE_ADDR
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-trusted-proxies
Class: HTTPS redirect bypass / IP-host spoof Reach: Remote
CakePHP 5.4.2 (887b641) - Cake Software Foundation
HttpsEnforcerMiddleware with trustedProxies => ['10.0.0.1'] calls setTrustedProxies, which sets trustProxy = true and never compares the list to REMOTE_ADDR. After that, scheme(), host(), and clientIp() honor attacker X-Forwarded-Proto / X-Forwarded-For / X-Forwarded-Host / X-Real-IP.
Default middleware has trustedProxies null and does not enable this. The documented load-balancer setup is the exposed case. An unauthenticated HTTP client who is not the listed proxy can skip the HTTPS redirect and spoof client IP and Host.
| ID | no CVE yet |
| Class | HTTPS redirect bypass / IP-host spoof |
| Reach | Remote (unauthenticated HTTP; app set trustedProxies) |
| CWE | CWE-441, CWE-346 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:N |
| Product | CakePHP |
| Affected | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | none. App set HttpsEnforcerMiddleware trustedProxies |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Needs an app that enabled trustedProxies (typical reverse-proxy HTTPS enforce). Does not need to connect from a listed proxy IP.
| Privilege | Method / sink | Lab-proven or inferred |
|---|---|---|
| Skip HTTPS redirect / HSTS path | GET / HTTP with X-Forwarded-Proto: https | Lab-proven. 200, scheme=https, witness in JSON |
Spoof clientIp() | X-Forwarded-For: 203.0.113.50 | Lab-proven. client_ip=203.0.113.50 |
Spoof host() | X-Forwarded-Host: spoof.invalid | Lab-proven. host=spoof.invalid |
Spoof via X-Real-IP | X-Real-IP: 198.51.100.9 | Lab-proven. client_ip=198.51.100.9 |
Bypass IP ACL / rate limit keyed on clientIp() | Same spoof | Inferred. RateLimitMiddleware default remote_addr is not this bug |
| Negative control | Same forwarded headers on /control (no trustedProxies) | Lab-proven. Still 301 to https |
Closed on this leftover: default trustedProxies => null; REMOTE_ADDR itself is still the Docker bridge IP in the lab (192.168.208.1, not the listed 10.0.0.1). Not RCE. Not a cookie-jar bug.
I pinned cakephp/cakephp 5.4.2. ServerRequest::setTrustedProxies():
public function setTrustedProxies(array $proxies): void
{
$this->trustedProxies = $proxies;
$this->trustProxy = true;
$this->uri = $this->uri->withScheme($this->scheme());
}
HttpsEnforcerMiddleware calls that whenever trustedProxies is non-null. The listed IPs are later used as an array_diff on the XFF chain, not as a check of the connecting peer.
Wrong turns already recorded: treating default middleware as this leftover (it is not); calling RateLimitMiddleware x-forwarded-for the same bug (5.4.1 bakery already moved that default to remote_addr); claiming REMOTE_ADDR itself was spoofed. Theatre: a reverse shell.
python3 cakephp-trusted-proxies-Abraxas-Labs.py
or
cd lab
./run.sh
Composer cakephp/cakephp 5.4.2 in PHP 8.3. Tiny app: / uses trustedProxies => ['10.0.0.1']; /control does not. Loopback HTTP at 127.0.0.1:19430.
/ no forwarded headers -> 301 https./control with proto/for/host/real-ip -> 301 https./ with X-Forwarded-Proto: https -> 200, scheme https, trust_proxy=true, REMOTE_ADDR is not 10.0.0.1./ with XFF + Host -> client_ip=203.0.113.50, host=spoof.invalid./ with X-Real-IP -> client_ip=198.51.100.9.SUCCESS cakephp-trusted-proxies pin=5.4.2 how=app remote-addr=192.168.208.1 listed-proxy=10.0.0.1 proto-bypass=200 control-redirect=301 client-ip=203.0.113.50 host=spoof.invalid x-real-ip=198.51.100.9 CAKEPHP-TRUSTED-PROXIES-WITNESS
Only honor forwarded headers when REMOTE_ADDR is in the trusted-proxy list (Symfony isFromTrustedProxy()). Empty list must not enable trust.
887b641de9f7aba06071f98f17edcbc573cbcf63)src/Http/ServerRequest.php · src/Http/Middleware/HttpsEnforcerMiddleware.phpGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.