Set precise Cache-Control and Vary headers in Workers and Pages so that user-specific responses never enter the shared edge cache.

Identify what Cloudflare actually caches

Cloudflare caches responses when a page rule or Worker sets Cache-Control to public with a positive max-age or s-maxage, or when the Cache Everything option is active. The cache key includes the URL path, query string (unless stripped), and any headers listed in a custom Cache Key definition. If a response varies by an unlisted header such as Authorization or a custom X-User-Id, the same cached object can be returned to subsequent visitors who never sent that header.

A common failure mode occurs when a Worker or origin returns Set-Cookie on a cacheable response. The cookie value travels with the cached body and is delivered to every subsequent request that matches the cache key, allowing session fixation or token leakage across users.

Set Cache-Control to exclude personalized responses

In a Worker, inspect the incoming request for cookies, Authorization, or any header that produces different HTML or JSON. If those headers are present, respond with Cache-Control: private, no-store so the edge never stores the object. For static assets that truly are identical for all visitors, use public, max-age=31536000, immutable and omit any Vary header that is not strictly required.

When using Pages, add a _headers file or a Worker that runs on every request. The file can declare /static/* Cache-Control: public, max-age=31536000 but must never apply the same directive to routes that read cookies or session state. Test the combination by sending two requests that differ only in a cookie value and confirm the second request receives a fresh response rather than the cached one.

Limit Vary to headers that actually change content

Vary tells the cache that the response body depends on the listed request headers. The minimal safe list is usually Accept-Encoding. Adding Cookie or Authorization to Vary creates a separate cache entry for every unique value, which defeats the purpose of the edge cache and can still leak data if an attacker can force a poisoned entry under a known Vary value.

Inside a Worker, delete or rewrite the Vary header before returning the response. Remove any header that contains user-specific data and replace it with Vary: Accept-Encoding only. If the origin must send additional Vary values, normalize them first so that only the presence or absence of a header, not its full value, affects the cache key.

Validate with controlled requests and purge on change

After deploying header logic, send identical requests that differ only in the headers you intend to vary on. Confirm that responses differ when they should and match when they should not. Use the cache purge API or a Worker that calls purge everything on a KV or D1 change that affects rendered content.

Log the CF-Cache-Status header on every response during testing. A value of HIT on a request that contains a private cookie is an immediate signal that the header rules are still too permissive. Adjust the Worker logic until private responses consistently return MISS or DYNAMIC.