RP-7005
criticalCache Poisoning via Spoofed X-Forwarded-Host on a Cached Response
Detects a cache HIT/cacheable response where the X-Forwarded-Host header the client sent does not match the real Host header. If the backend trusts X-Forwarded-Host to build absolute URLs (password reset links, redirects, asset URLs) but the cache key doesn't include that header, an attacker can poison the shared cache with a response containing their own attacker-controlled links - served to every subsequent visitor who hits the same cache key.
Detection logic
Fires as soon as one event matches: `cache_status` is "HIT" AND `X-Forwarded-Host` is "Host".
{
"detection_type": "selection",
"selection": {
"cache_status": "HIT",
"X-Forwarded-Host|neq_field": "Host"
}
}Log source: category=reverse_proxy · Event ID(s): rp_access_log
Required log fields
- client_ip
- Host
- X-Forwarded-Host
- cache_status
- uri
Enabling this in your environment
Where: Reverse proxy / CDN access log configuration - log the request's X-Forwarded-Host header value and the cache HIT/MISS/BYPASS status per request
nginx: log_format including $http_x_forwarded_host and $upstream_cache_status; a CDN's edge logging config for the equivalent forwarded-host and cache-status fields.
The real fix is including X-Forwarded-Host (or dropping/normalizing it entirely) in the cache key, not just detecting after a poisoned response is already cached and being served.
False positives
- A legitimate internal service-to-service call that intentionally sets X-Forwarded-Host while proxying on behalf of another vhost - confirm the cache key strategy actually accounts for this before assuming poisoning