HTTP Security Headers

Cache-Control

The master switch for caching: how long a response can be reused, whether shared caches may store it, and when it must be revalidated — with real security implications.

What it is

Cache-Control (RFC 9111) is the primary header for controlling caching behavior in browsers, CDNs and proxies. It decides whether a response can be stored, by whom, for how long, and whether it must be revalidated before reuse. Getting it wrong ranges from wasted bandwidth to caching a private, authenticated response in a shared cache where another user can retrieve it.

Key directives

max-age=<sec>
How long the response is fresh, in seconds.
s-maxage=<sec>
Overrides max-age for shared caches (CDNs/proxies) only.
no-cache
May be stored, but must revalidate with the origin before every reuse.
no-store
Must not be stored anywhere. Use for sensitive, user-specific responses.
private
May be cached by the browser but NOT by shared caches. Use for authenticated pages.
public
May be cached by any cache, even if the request had Authorization.
immutable
The response will never change during its freshness lifetime, so the browser skips revalidation on reload.
stale-while-revalidate=<sec>
Serve stale content while revalidating in the background.
must-revalidate
Once stale, the cache must revalidate and not serve a stale copy on error.
HTTP RESPONSE HEADERS
# Long-lived, fingerprinted static asset
Cache-Control: public, max-age=31536000, immutable

# Authenticated HTML page
Cache-Control: private, no-cache

# Sensitive response (never store)
Cache-Control: no-store

Why it matters

  • Correct caching of fingerprinted assets (immutable, one-year max-age) is one of the biggest front-end performance wins available.
  • private / no-store on authenticated responses prevents a shared cache or CDN from serving one user's data to another — a real, common breach vector.
  • Cache directives interact with the Vary header; mis-set caching can serve the wrong language, encoding or auth state.

Common mistakes

  • Marking an authenticated page public (or omitting private), letting a CDN cache and serve user-specific data to others.
  • Using no-cache when you mean no-storeno-cache still stores the response, it just revalidates it.
  • Caching HTML with a long max-age and no fingerprinting, so users get stale pages after a deploy.
  • Setting immutable on content that actually changes, causing users to see outdated files until a hard reload.

How WebInspect checks this

  • WebInspect parses Cache-Control and reports freshness lifetime, shared-cache eligibility and revalidation behavior.
  • It flags authenticated or personalized responses that are cacheable by shared caches (missing private/no-store).
  • It highlights static assets that lack long-lived caching and could be served with immutable for a performance gain.