About CDN Cache Poisoning Attack
Overview
CDN cache poisoning occurs when an attacker tricks a CDN into caching a malicious or broken response, which is then served to legitimate users. The attack exploits mismatches between what the CDN uses as a cache key and what actually influences the origin’s response.
Real-World Examples
Example 1: Middleware Debug Header Poisoning
Background
A middleware supports a debug header intended for testing. When present, it causes the middleware to return a blank page. The CDN in front of the service caches responses keyed by URL and query string only — the debug header is not part of the cache key.
Attack Flow
- The attacker sends a request to
https://www.example.com/with the debug header included. - The middleware returns a blank page.
- The CDN caches the blank page under the cache key for
/. - A normal user visits the same URL without the debug header.
- The CDN serves the cached blank page, denying service to all users until the cache expires.
Root Cause
The cache key does not account for a header that changes the response. A response triggered by a non-standard header gets served to everyone requesting the same URL.
Example 2: URL Length Discrepancy Between CDN and Nginx
Background
The CDN caches responses by URL path only (ignoring query strings), because the application itself ignores query strings. Between the CDN and the application sits an Nginx reverse proxy. Critically, Nginx enforces a smaller maximum URL length than the CDN does.
Attack Flow
- The attacker sends a request with an oversized query string, e.g.,
https://www.example.com/login?q=xxx...xxx(very long). - The total URL length exceeds Nginx’s limit but stays within the CDN’s limit.
- The CDN forwards the request to Nginx, which rejects it with an error page.
- The CDN caches the error page under the cache key
/login(path only, query string ignored). - A normal user visits
/loginand receives the cached error page instead of the login form.
Root Cause
A mismatch in URL length limits between the CDN and Nginx, combined with a path-only cache key and the CDN’s willingness to cache error responses, allows an attacker to poison the cache for any route.
Prevention Strategies
Include all response-varying inputs in the cache key.Any header, cookie, or parameter that changes the origin’s response must be part of the cache key.
Respect origin cache-control headers.Always honor the
Cache-Controlheader from your application rather than relying on a default TTL configured at the CDN level.Strip unnecessary request components before forwarding.If the origin does not use query strings, configure the CDN to remove them before forwarding to the backend — this eliminates an entire class of poisoning vectors.
Do not cache error or non-200 responses.A cached error page will be served to all subsequent users hitting that cache key.
Do not cache paths that return sensitive or personalized content.Caching such responses introduces a related vulnerability known as Web Cache Deception (WCD).
Do not cache solely based on file extension.Caching anything ending in
.jpgor.cssregardless of the actual response content-type can be exploited. Where supported, include the responseContent-Typein caching decisions.Serve static assets from a dedicated domain.Using a separate origin (e.g.,
static.example.com) for static resources isolates the caching layer from your dynamic application logic.