Preventing sensitive data from being cached is less about one perfect header and more about building a repeatable review process across browsers, CDNs, reverse proxies, service workers, and application code. This checklist is designed for teams that ship authenticated pages, APIs, dashboards, and account workflows, and want a practical way to reduce the risk of private content being stored or served from the wrong cache layer.
Overview
If your application uses caching anywhere, you need a clear rule for which responses may be stored and which must never persist beyond the current request. The risk is easy to underestimate because caching is distributed by design. A response can be cached by the browser, a shared proxy, a CDN, an application gateway, a service worker, or even a custom client.
That means “we disabled caching” is rarely enough on its own. You need to verify behavior at each layer.
As a working principle, treat the following as sensitive unless you have explicitly decided otherwise:
- Authenticated HTML pages
- User-specific API responses
- Account settings and billing pages
- Admin panels and internal tools
- Responses containing tokens, session details, or personal data
- Downloads generated per user
- Error pages that may echo private request data
For most sensitive responses, a conservative default is to send cache directives that prevent storage by shared caches and discourage browser reuse after logout or back-button navigation. In practice, many teams start with Cache-Control: no-store for private content and then make narrower exceptions only where they have a strong reason and a test plan.
This article gives you a reusable checklist by scenario, followed by the implementation details that are easy to miss.
Checklist by scenario
Use this section before you ship new endpoints, update authentication flows, or move traffic behind a CDN.
1. Authenticated HTML pages
Examples: dashboards, profile pages, order history, internal admin screens.
- Set a strict cache policy at the origin. For the most sensitive pages, prefer
Cache-Control: no-store. - Do not rely on default framework behavior for logged-in routes. Confirm the actual response headers in production-like environments.
- Avoid serving authenticated HTML through generic “cache everything” CDN rules.
- Make sure reverse proxies do not ignore origin headers or apply broad cache rules to HTML.
- If you vary content by cookie or authorization state, verify that shared caches never store one user’s version for another.
- Test logout behavior with back-button navigation and hard refresh.
If your team is tuning broader cache behavior, it helps to compare this page-level policy against your public content strategy. Related reading: Common Cache-Control Header Mistakes and How to Fix Them.
2. Authenticated API responses
Examples: /me, account data, private notifications, internal reporting endpoints.
- Assume private APIs should not be cached by shared intermediaries.
- If the response includes user-specific data, use headers that prevent shared storage. In many cases,
no-storeis appropriate. - Be especially careful when requests use an
Authorizationheader or session cookie. Do not assume every intermediary handles those safely by default. - Review whether API gateways, edge workers, or reverse proxies override cache behavior.
- Do not key caches on URL alone if the response changes by user identity.
- For mobile apps or custom clients, review local response caching too.
If you intentionally cache API content, do it only for clearly public or anonymous responses and document why those endpoints are safe. For infrastructure-specific patterns, see Varnish Cache Configuration Patterns for APIs and Content Sites.
3. Pages that mix public and private data
Examples: a mostly static page with a signed-in header, personalized recommendations, account badge, or usage metrics.
- Separate public shell content from private fragments whenever possible.
- Do not cache the assembled page in a shared layer if it contains user-specific data.
- Move personalization to client-side requests that are individually protected from storage, if that fits your architecture.
- Review edge-side includes or fragment caching carefully. A safe public component can become unsafe when combined with personalized output.
- Confirm that any service worker logic does not cache the mixed response for later replay.
This is a common failure mode: a page looks mostly public, so it gets broad caching treatment, but a small private fragment makes the whole response sensitive.
4. Login, logout, password reset, and account recovery flows
- Mark login and password-related pages as non-storable.
- Prevent caching of responses that include reset tokens, magic links, or account recovery details.
- After logout, make sure old authenticated pages are not displayed from browser history or an offline cache.
- Invalidate or bypass any service worker caches that may hold account pages.
- Test cross-device and shared-device scenarios, especially on kiosk-style setups or managed desktops.
These routes are often small, but they are high-value targets because they can expose credentials, token-bearing links, or account state.
5. File downloads and exports
Examples: invoices, user reports, CSV exports, generated PDFs, support archives.
- Set explicit headers for generated files rather than inheriting defaults from the file server or object storage layer.
- Treat per-user exports as private even if the underlying source data is not highly sensitive.
- Check CDN behavior for signed URLs and attachment responses.
- Be careful with temporary URLs: the URL itself may grant access, even if the file is not cached long term.
- Review browser caching and download manager behavior for repeat access.
Generated documents often slip through review because they are not part of the main app templates, but they frequently contain billing, address, or internal account information.
6. Error responses and debug endpoints
- Inspect 4xx and 5xx responses for sensitive content such as stack traces, request payload echoes, or internal identifiers.
- Do not let error pages inherit permissive cache settings from your normal HTML templates.
- Disable or restrict debug endpoints in production.
- Review custom maintenance pages and origin-failover responses at the CDN edge.
Even a correctly protected application can leak details if an error response is cached and replayed broadly.
7. Service workers and offline support
- Audit route matching rules in your service worker.
- Exclude authenticated HTML and private APIs from cache-first or stale-while-revalidate patterns unless you have a very specific, tested design.
- Clear cached private entries on logout or session expiration where applicable.
- Test offline behavior with a signed-in user, then sign out and verify what remains accessible.
Service workers are their own cache layer, and they can override your expectations even if server headers are correct. For a deeper comparison of strategies, see Service Worker Caching Strategies Compared.
8. CDN and edge configuration
- Review all page rules, cache rules, and edge logic for authenticated paths.
- Exclude account, admin, checkout, billing, and private API prefixes from broad caching rules.
- Check whether cookies are stripped, ignored, or normalized in a way that affects cache keys.
- Verify that edge caching does not override strict origin directives for private responses.
- Document exceptions clearly so future performance work does not accidentally widen caching scope.
If you use Cloudflare or a similar edge platform, rule order and default behavior matter as much as the origin header itself. See Cloudflare Cache Rules Explained with Practical Examples.
What to double-check
This is the review list to run before release, after infrastructure changes, and during security hardening work.
Header behavior in the real response
- Inspect the final response from the public URL, not just application code.
- Confirm that origin, proxy, and CDN do not conflict.
- Look for
Cache-Control,Pragmaif used for compatibility, and any surrogate or CDN-specific headers. - Check whether redirects carry safe cache headers too.
Shared versus private caching
One of the easiest mistakes is using a directive that sounds strict but still allows some storage. If the response is truly sensitive, ask a simple question: should any cache store this at all? If the answer is no, use a policy aligned with that outcome and validate it end to end.
Cache keys and user separation
- Verify whether cache entries vary by cookie, authorization header, locale, device, or tenant.
- Do not assume path-based separation is enough for multi-tenant or role-based applications.
- Review edge includes, SSR caches, and application fragment caches separately.
Logout and session expiration behavior
- Sign in, visit private pages, sign out, then use the back button.
- Test multiple browsers and private windows.
- Test with disabled JavaScript if your app still renders server responses.
- Verify mobile WebView behavior if your product uses embedded browsers.
Framework defaults
Some frameworks, platforms, and serverless layers add caching behavior for static optimization, route handlers, or pre-rendered responses. Double-check what happens when a route becomes authenticated later, or when personalization is introduced into a previously public page.
Observability and incident response
- Log cache status where practical, such as edge cache hits and misses.
- Make private-route cache checks part of smoke tests.
- Have a purge plan ready if a private page is accidentally cached.
If you need to prepare for rollback or cleanup, this can pair well with CDN Cache Purge Strategies: Full Purge vs Tag Purge vs URL Purge.
Common mistakes
These issues show up often because they come from reasonable assumptions that turn out to be incomplete.
Using one header policy for all HTML
Public marketing pages and authenticated dashboards should not share the same caching rules. Splitting routes by content sensitivity is usually safer than trying to fine-tune a single policy everywhere.
Trusting the browser-only outcome
A page may appear correct in a local browser test while still being stored by a CDN or proxy. Always test through the full delivery path.
Caching responses that depend on cookies
If a response changes based on session or identity cookies, broad shared caching is dangerous unless you have explicit cache key design and strong isolation. In many applications, it is simpler and safer not to cache those responses at all.
Forgetting service workers
Teams may remove CDN caching from private pages but leave a cache-first service worker rule in place. That can keep account content available after logout or during offline use.
Leaving generated files on permissive defaults
Exports, invoices, and PDFs often inherit static-asset rules by accident. Review them separately from your image and asset strategy. For public static assets, long-lived caching may be ideal, as discussed in Immutable Caching for Versioned Assets, but that logic should not spill into private documents.
Applying “cache everything” without exclusions
Performance tuning at the CDN edge can unintentionally sweep in login states, dashboards, and account flows. Every broad rule should come with an explicit exclusion list for private paths.
Not testing stale responses
Even if a page should no longer be cached, stale content may still exist somewhere. That is why purge procedures and route audits matter. If your team uses stale controls for resilience on public content, keep those patterns away from authenticated data unless you have a very deliberate exception. Related reading: Stale-While-Revalidate vs Stale-If-Error: Practical Use Cases.
When to revisit
This checklist is most useful when treated as a living review, not a one-time setup. Revisit it whenever your app, delivery stack, or workflow changes.
- Before launching a new authenticated section or admin tool
- When introducing a CDN, reverse proxy, or edge worker
- When changing framework rendering mode, SSR behavior, or route handling
- When adding a service worker, offline mode, or app shell
- When moving file delivery to object storage or signed URLs
- When changing login, logout, or session management flows
- Before seasonal traffic planning or broader cache optimization work
- After any incident involving stale, leaked, or misrouted content
A practical way to operationalize this is to add a short “cache sensitivity” check to pull requests and architecture reviews:
- Does this route return user-specific or confidential data?
- Which cache layers can see it?
- Should any layer store it?
- What headers and rules enforce that decision?
- How will we test logout, back-button, stale, and edge behavior?
Finally, keep your caching guidance split into two documents: one for public performance optimization and one for private-response protection. That separation reduces the chance that an aggressive optimization meant for images, versioned assets, or public content gets copied onto authenticated routes. If you are reviewing your broader cache design, the supporting guides on TTL tuning and cache headers for static assets and HTML can help you keep those two worlds clearly separated.
The simplest durable rule is still a good one: if a response would be a problem when shown to the wrong person, do not let it be cached until you have explicitly proved the storage layer, cache key, and invalidation behavior are safe.