Browser caches and shared caches present different risks
A private HTTP cache belongs to an individual user context, such as a browser profile. A shared cache can reuse responses for several users, for example in a CDN or reverse proxy. Personalised content must not accidentally reach other people as a public variant. On shared devices, there is also the question of which data remains accessible within the browser profile. RFC 9111 §§ 1–3
A missing Cache-Control header proves neither data leakage nor an absence of caching. Depending on the status, other metadata and the cache, a response may be stored and treated as fresh heuristically even without an explicit lifetime. Public caching is useful for suitable content.
The Web Security Check reads directives and recognisable CDN signals from the final response. It does not know all of your application's data, login states and cache rules. It performs neither an access test with two accounts nor a complete cache delivery test. Its classification is therefore a prompt to examine the response context.
What each directive means
On narrow screens, scroll the table sideways.
| Directive | Meaning for conforming HTTP caches | Important limitation |
|---|---|---|
no-store | Do not store the request or response concerned, or use the response for other requests. | Not a general deletion command for earlier copies or application storage. |
no-cache | Storage is allowed; reuse requires successful validation. | The content may already be in the cache. |
private | Shared caches must not store the response; private caches may do so under the remaining rules. | Does not mean encryption or protection from other people using the same browser profile. |
public | Explicitly permits caching under the remaining rules, including in certain otherwise restricted cases. | Not suitable as blanket permission for personalised content. |
max-age=N | Freshness lifetime in seconds; the age already reached counts towards it. | Does not guarantee that a copy will actually be stored. |
s-maxage=N | A specific freshness lifetime for shared caches, taking precedence over max-age/Expires. | Can also permit caching of responses to requests with Authorization. |
must-revalidate | Do not reuse a response after its freshness lifetime without successful validation. | Allows earlier storage; not equivalent to no-cache. |
immutable | Signals that content will not change during its freshness lifetime; avoids unnecessary normal revalidation. | Neither indefinite caching nor a prohibition on an explicitly forced reload. |
The first rules are specified in RFC 9111 § 5.2, and immutable in RFC 8246 § 2. The table uses private and no-cache without a field-name list. Qualified forms such as private="Set-Cookie" apply only to the named header fields; they do not prohibit storage of the entire content.
For a straightforward prohibition on storage, Cache-Control: no-store is sufficient. Adding private, no-cache and must-revalidate is not necessary for that purpose. Do not combine special directives mechanically: must-understand, for example, has explicitly defined interactions with no-store. As a response field, Pragma: no-cache is not a reliably specified replacement for Cache-Control. RFC 9111 §§ 5.2.2.3, 5.4
Revalidation saves transfer, but does not necessarily avoid storage
With no-cache, a browser can validate a stored response using its ETag through If-None-Match. A corresponding 304 Not Modified confirms that the existing representation can continue to be used; it does not transfer the entire content again. Access control and variant selection must still be correct. A validator is not an authorisation.
In the documented local test, Chromium used a fresh response without a second server request, validated no-cache with a conditional request, and fetched no-store again without a cache validator. This checks that private browser cache, not a real CDN.
Examples by content and purpose
On narrow screens, scroll the table sideways.
| Response | Possible setting | Prerequisite |
|---|---|---|
| Personal account data, reset information or a sensitive API response | Cache-Control: no-store | This content should not be stored in the HTTP cache. |
| A user-specific response that may be stored locally but must be checked for freshness before use | Cache-Control: private, no-cache | Storage in a private cache is acceptable; successful validation is required. |
| A public page for which some delay in updates is acceptable | Cache-Control: public, max-age=3600 | No personalised variant is mixed in under the same cache key; one hour is an example choice. |
| A public asset with an immutable, content-based address | Cache-Control: public, max-age=31536000, immutable | Every content change gets a new URL; old versions remain available to existing documents. |
The route name alone does not decide this. A public login shell may have different requirements from the personal data it loads. A JSON response may be public or confidential. The values apply to the individual response, not automatically to all subresources.
For long lifetimes, plan rollback in advance: an already fresh browser cache may not learn about a new server policy until the next request. New asset URLs and a targeted CDN purge may be necessary; a current no-store response does not reliably remove every previously stored version.
Variants, cookies and Authorization
Vary names request headers whose values must be considered when selecting a stored variant. For example, Vary: Accept-Encoding can distinguish compressed response variants. Neither Vary: Cookie nor Vary: Authorization is a user permission or a replacement for an intended prohibition on storage. RFC 9111 § 4.1
For requests with Authorization, RFC 9111 already restricts reuse in shared caches. Certain response directives — public, s-maxage and must-revalidate — can permit it under their respective conditions. These rules do not automatically apply to every cookie-based login. A Set-Cookie header alone is not a universal prohibition on storage either. RFC 9111 §§ 3.5, 7.3
Check the actual CDN cache key and rules such as ‘cache everything’, query normalisation and cookie exceptions. A variant list that the CDN ignores or handles differently cannot be fixed simply by adding another header.
Check HTTP caching, bfcache and service workers separately
The back-forward cache (bfcache) can retain a whole document state, including JavaScript state, for back/forward navigation. This is a different mechanism from the HTTP cache. Under certain conditions, Chrome also allows pages with no-store into bfcache, taking changes to cookies and other authorisation signals into account, among other things. Chrome: bfcache and no-store
A documented local Chromium 147 test restored a no-store page from bfcache without a cookie change. pageshow with event.persisted indicated that restoration. This disproves the claim that ‘no-store prevents every return to an old view’, but is not acceptance evidence for a logout flow. After logout, an account change and in a second tab, check both visible content and access rights enforced by the server.
The Cache API, in turn, is application-controlled storage, often used with service workers. Its put() does not automatically obey a prohibition on HTTP caching. In the documented local counterexample, JavaScript could store a response with no-store there and read it again. Application offline features and service worker routes therefore need their own rules for personal data. Service Workers: Cache.put
Verify a cache change with evidence
- List response types and states: public, logged in, logged out, errors and redirects. Identify which content may be stored or shared.
- Check the origin, proxy and CDN in the actual delivery path. GET and HEAD can be configured differently; a GET better represents a content request.
- Use synthetic accounts A and B in an isolated test: warm the cache, access the page with the other account, and test logout followed by another access attempt. No user may receive another user's content.
- Examine server requests, status,
Age, validators and vendor-specific cache status fields together. Browser developer tools with ‘Disable cache’ enabled change the experiment and do not provide a normal cache test. - Test back/forward navigation, open tabs, offline paths and service workers separately. Clearing data through Clear-Site-Data is a targeted additional measure with its own scope.
In web cache deception, the cache and application interpret URLs or routing differently. A URL such as /konto/datei.css becomes a problem only when it returns personalised content that is stored or shared inappropriately. Your own tests therefore need routing counterexamples and a content comparison; the filename extension or an individual header does not prove an attack.
A cache finding is not a legal verdict
The security assessment depends on the actual content, its accessibility and the application context. A missing no-store alone establishes neither a data protection breach nor a particular fine. Conversely, the header does not prove complete confidentiality or NIS2 compliance. The compliance overview puts individual technical measures in context.
Frequently asked questions
Does no-cache mean that nothing is stored?
No. It requires successful validation before reuse. To prohibit storage of the HTTP response concerned, use no-store.
Is private sufficient on a shared computer?
It prohibits storage in shared HTTP caches, but does not automatically protect local browser content from the next person using the computer. Assess storage needs, logout and device use separately.
Does every authenticated response need Vary: Authorization?
No. Vary selects variants. The Authorization rules, the data involved and the intended storage behaviour together determine the appropriate strategy.
Is public inherently unsafe?
It is useful for suitable public content. It must not allow unintended shared reuse of personalised responses.
Sources and technical reference date
Source reference date: 27 September 2026. RFC 9111 is the current HTTP caching specification and replaces RFC 7234; its errata were read with their status during that review. RFC 8246 adds immutable. Vendor and service worker sources are linked beside the relevant statements. The local tests from that source review used Chromium 147.0.7727.15 for a private HTTP cache, the Cache API and a targeted bfcache counterexample; no production shared cache or customer account was tested.