
CDN cache poisoning occurs when an attacker-controlled request input changes a response, but that input is not safely handled or properly represented in the cache key. The altered response can then be stored by a shared CDN cache and served to other users. The risky input may be a query parameter, a Host-related header, a forwarded header, a cookie, a protocol hint, a normalized path, or a value used by the origin to generate absolute URLs.
The central defensive rule is straightforward: if an input can change the response body, status, or important response headers, it must be included in the cache key, normalized or rejected before the application uses it, or prevented from reaching a shared cache. Adding every possible field to the cache key is not a complete solution because it can destroy cache efficiency and create a large number of variants. The goal is to align the cache policy with the origin's actual response variation.
Configuration details and sources in this article were reviewed on August 10, 2026. The examples are intended for defensive validation and do not include payloads designed for use against production websites. CloudFront, AWS WAF, and related capabilities can change; verify current behavior in the official documentation and console.
What Conditions Make Cache Poisoning Possible?
A cache poisoning issue that affects other users usually requires all of the following:
The request contains an input that an attacker can control.
The origin or edge code uses that input to change the response.
The input is missing from the cache key or is normalized inconsistently across components.
The resulting response is eligible for CDN caching.
A later request from another user reaches the same cached object.
If the application safely ignores the input, the response does not change. If the response never enters a shared cache, the impact normally remains limited to one request. If the input is accurately included in the cache key, an attacker is more likely to create an isolated variant than overwrite the object used by ordinary visitors. The practical audit question is whether the origin's response dimensions match the CDN's cache dimensions.
What Is Included in a Cache Key?
A cache key is the identifier a cache uses to decide whether two requests can share one stored response. HTTP caching starts with the request method and target URI. A CDN can also vary the key using selected query strings, headers, and cookies.
In CloudFront, a cache policy controls which query strings, headers, and cookies are included in the cache key. Values included in the cache key are also sent to the origin. An origin request policy can forward additional values without adding them to the cache key. That separation is useful, but it creates an important review point:
High-risk configuration: a header, cookie, or query parameter is forwarded to the origin and changes its response, but is not included in the cache key. Requests with different inputs may then share one cached object.
| Input | Effect on Response | Recommended Treatment |
|---|---|---|
| Analytics-only parameter | No content change | Remove it from the cache key and origin request, or strip it consistently at the edge |
| Language, device, or format parameter | Returns a genuine content variant | Include it in the cache key and restrict accepted values |
| Login or user-session cookie | Returns private content | Normally bypass shared caching or use a separately reviewed private-cache design |
| Untrusted forwarding header | Can alter redirects, scripts, or absolute URLs | Remove, overwrite, or strictly validate it |
| Diagnostic header used only for origin logging | No response change | It can be forwarded without entering the key, but that assumption should be tested |
Why Are Host Headers a Major Risk?
Applications frequently use the Host value or a similar forwarded host header to generate canonical links, password-reset URLs, redirects, asset URLs, and security policies. If an application accepts arbitrary hostnames and reflects them into a cacheable response, an unexpected domain can be stored in a page or response header.
Multiple proxy layers create several possible sources of host information: the original Host, X-Forwarded-Host, CDN-generated headers, and the framework's own idea of the public URL. If separate layers select different sources, the configuration reviewed by the security team may not match the value actually consumed by the application.
Host header defenses
Maintain a hostname allowlist: Accept only verified business domains at the earliest practical entry point. Reject unknown hosts.
Do not generate sensitive links from user input: Use a server-side canonical domain for reset links, callback URLs, and other security-sensitive destinations.
Sanitize forwarded host headers: Do not forward
X-Forwarded-Hostor similar fields unless required. When required, have a trusted proxy generate or overwrite them.Separate trust boundaries: Admin applications, customer custom domains, and public sites may require separate cache behaviors, origins, or distributions.
Review redirects and error pages: An invalid Host value should not be reflected into cacheable 3xx or 4xx responses or a
Locationheader.
Adding Host-derived input to the cache key should not be the only fix. It may create a large number of attacker-controlled variants and still allows an individual user to receive a malicious link. Rejecting unknown hosts and using a trusted canonical hostname remains the stronger design.
Should Query Parameters Be Included, Ignored, or Allowlisted?
Query parameters are a common source of disagreement between the CDN and origin. Each broad strategy has limits:
| Strategy | Appropriate When | Main Risk |
|---|---|---|
| Ignore all parameters | No parameter can change the response | If the origin actually uses one parameter, different responses may share a cache entry |
| Include all parameters | The parameter set is controlled and every value creates a legitimate variant | Junk parameters and high-cardinality values reduce hit ratio and expand the cache |
| Allowlist selected parameters | Only a small known set changes content | A new application parameter may be introduced without updating the cache policy |
An allowlist is usually the most manageable option. Include only parameters that clearly change public content, such as a controlled language, image format, or page value. Strip advertising and analytics parameters at the edge, or ensure that the origin never uses them to generate a different response.
Test order, duplicate parameters, and encoding
AWS documentation notes that CloudFront caches according to query string names and values and that a different parameter order can create a separate cached object. Application frameworks may also interpret duplicate parameters, case, empty values, and percent encoding differently. Normalize order and encoding, constrain allowed names and values, and avoid giving the CDN, WAF, and application incompatible parsing rules.
How Should Headers Be Used in a CloudFront Cache Policy?
More headers do not automatically mean more security. Including every viewer header in the cache key can severely reduce cache hit ratio because browser versions, tracing identifiers, and temporary headers create many variants. Build a minimal allowlist based on genuine response differences.
Accept-Encoding: Use the compression controls provided by the CloudFront cache policy instead of building overlapping custom variants.Origin: If CORS responses vary by origin, align the cache and CORS policies. A fixed origin allowlist must still be validated at the edge or origin.Device or language headers: Include them only when the origin returns a different object, and normalize them into a small number of categories.
Forwarding and rewrite headers: Do not trust viewer-supplied
X-Forwarded-*values. Have a trusted proxy create or replace them.Debug headers: A public request header should not enable a debug mode that changes a cacheable production page.
The Vary response header can describe which request headers affect a response, but a CDN deployment must still verify the product's cache policy and actual behavior. Adding Vary at the origin is not a substitute for confirming how edge objects are differentiated.
How Can Path Normalization Create Cache Confusion?
Cache-key safety extends beyond headers and parameters. A CDN, load balancer, web server, and application framework may handle repeated slashes, dot segments, case, percent encoding, and trailing slashes differently. If one layer treats two paths as equivalent while another treats them as different—or the reverse—the result can be cache confusion.
Choose one clear layer for path normalization and ensure that later components do not reinterpret the path using different rules. Returning a non-cacheable 4xx response for invalid paths is often easier to audit than performing multiple implicit rewrites.
Which Responses Should Never Enter a Shared Cache?
Pages containing a person's account, order, authorization, or profile information.
Responses generated from a login cookie, session state, or
Authorizationheader.Password resets, email verification, payment callbacks, and similar sensitive workflows.
Debug output, stack traces, and internal diagnostics.
Redirects or error pages generated from unnormalized request input.
Use appropriate Cache-Control, CloudFront behavior settings, and application design to keep these responses out of shared caches. Hiding sensitive data with front-end JavaScript is not enough because the CDN stores the HTTP response it receives.
A CloudFront Defense Checklist
Map response variation by path: Document which parameters, headers, and cookies change content for every cache behavior.
Select or create a cache policy: Add only necessary inputs to the key and normalize high-cardinality values.
Review the origin request policy: Identify every value forwarded without entering the key and prove that it cannot change the response.
Enforce trusted hosts: Accept only configured domains and remove viewer-controlled forwarded host fields.
Control cacheable status codes and TTLs: Give redirects, error pages, and dynamic content lifetimes appropriate to their risk.
Constrain input with AWS WAF: Block or count unexpected headers, invalid hostnames, and parameters that should not appear.
Review edge code: If CloudFront Functions or Lambda@Edge modifies the URI, headers, or response, audit its execution order against cache-key construction.
Version configuration: Track cache policies, origin request policies, WAF rules, and edge functions so changes can be reviewed and rolled back.
A useful review question is: if this field were removed from the cache key, could the origin still return a different response? If the answer is yes, include it, normalize it, or prevent the response from being shared.
How Can Cache Poisoning Be Tested Safely?
Testing should take place in a development environment, a staging hostname, or an explicitly authorized production window. Do not send dangerous input into a public production cache. A lower-risk validation sequence is:
Use a test path or randomized object name that ordinary users will not request.
Add a harmless and recognizable marker to the test request.
Change one query parameter, header, or cookie at a time and observe whether the response changes.
Send a fresh request without the marker and check whether the previous response appears.
Review
Age, cache-result headers, request IDs, and access logs to confirm whether the response came from cache.Repeat the test from more than one edge location before treating the result as global.
Remove test objects and restore temporary settings after validation.
A single cache hit or reflected value is not enough to confirm cache poisoning. The test must show that a controllable input changed the response, was not distinguished by the cache key, and was later served to a request that did not contain the input.
What Warning Signs Should Be Monitored?
A sudden increase in unique query parameters or cookie combinations on one path.
Growth in unknown Host values, forwarded host headers, or unusual protocol headers.
A falling cache hit ratio combined with more objects or origin requests.
Unexpected domains, redirects, scripts, or security headers appearing on normal pages.
Different response hashes being associated with what should be the same public cache variant.
Error responses remaining cached for long periods or appearing in multiple regions.
A matching increase in AWS WAF count rules and unusual CloudFront log fields.
Logs can contain cookies, query strings, and client information. Apply data minimization, access controls, and a defined retention period. Retaining every raw request indefinitely for possible security analysis creates its own privacy and compliance risks.
How Should a Suspected Cache Poisoning Incident Be Handled?
Block the input first: Reject the value that changes the response at the CDN, WAF, or origin.
Pause caching on affected paths: Reduce TTL or temporarily bypass shared caching until the cause is corrected.
Fix the cache key or application logic: Invalidating objects alone allows the same issue to return.
Invalidate precisely: After the fix is deployed, purge confirmed paths and broaden the scope only when the impact cannot be bounded.
Check every cache layer: Browsers, reverse proxies, CloudFront, and application caches may each retain a copy.
Determine propagation: Analyze logs by edge location, time window, Host, and path.
Rotate exposed data: If responses disclosed tokens, links, or sensitive information, revoke and replace them through the incident-response process.
The order matters: fix the input path and response logic before invalidating the cache. If the vulnerability remains open, a new poisoned response can be cached immediately after the purge.
Common Mistakes
Adding every request field to the cache key
This creates many low-hit variants and can turn arbitrary input into cache-capacity consumption. A cache key should be minimal but complete, not unlimited.
Assuming HTTPS prevents cache poisoning
HTTPS protects data in transit. It does not correct disagreements between the CDN and origin about cache keys, request input, or response variation.
Deploying a WAF rule without fixing the origin
A WAF can reduce known malformed input but cannot understand every application rule. The origin should still reject unknown hosts, avoid reflecting untrusted values, and correctly mark private responses.
Purging the entire site without correcting the cause
A full invalidation reduces hit ratio and increases origin load while doing nothing to prevent reinfection. Fix the cause first and then purge the confirmed scope.
Frequently Asked Questions
Is CDN cache poisoning the same as browser cache poisoning?
No. A CDN is a shared cache, so one stored response can affect many users. A browser cache normally affects one client. Both layers can still be involved in the same delivery path.
Is ignoring every query parameter the safest option?
No. If the origin uses one parameter to return different content while the CDN ignores it, different responses may incorrectly share one cache entry. Base the policy on actual application behavior.
Does adding all query parameters to the cache key solve the problem?
No. Headers, cookies, path normalization, and edge code can also create unsafe differences. Including every parameter can additionally produce cache fragmentation and resource consumption.
Can a CloudFront managed cache policy be used directly?
It can be a useful starting point, but it must still match the origin. What matters is not who created the policy, but whether every response-changing input is handled consistently.
What if dynamic pages need CDN caching?
Define a limited set of genuinely public variants, such as controlled language, device, or region categories. Do not mix user identity, authorization, or private data into a shared response. If the public variants cannot be clearly defined, do not cache the page.
Conclusion
CDN cache poisoning is fundamentally a disagreement between the cache and origin about which inputs change a response. The most reliable defense is not an ever-growing collection of rules, but a clear contract for each cache behavior: which hosts are valid, which query parameters, headers, and cookies enter the cache key, which values may only be forwarded, and which responses must never be shared.
For CloudFront, pay special attention to the combination of Cache Policy and Origin Request Policy, especially any value that is forwarded to the origin without entering the cache key. Add hostname allowlisting, parameter normalization, WAF constraints, authorized testing, log monitoring, and an incident process that fixes the cause before invalidation. This approach reduces cache poisoning risk without unnecessarily sacrificing cache hit ratio.
CloudFlew provides CDN services based on CloudFront. Before changing cache behavior, inventory the domains, query parameters, headers, and cookies that actually alter the response, and then design the smallest complete cache key for the application.
References
AWS CloudFront Developer Guide: Understand the cache key, reviewed August 10, 2026
AWS CloudFront Developer Guide: Control the cache key with a policy, reviewed August 10, 2026
AWS CloudFront Developer Guide: Cache content based on query string parameters, reviewed August 10, 2026
AWS CloudFront Developer Guide: Cache content based on request headers, reviewed August 10, 2026
AWS WAF Developer Guide: Request component options, reviewed August 10, 2026
IETF RFC 9111: HTTP Caching, reviewed August 10, 2026
PortSwigger Web Security Academy: Web cache poisoning, reviewed August 10, 2026