RoastMyOpsec

Safety

Cache-Control public vs private for Personalized Pages

May 17, 2022

Cache-Control public vs private is a shared-cache decision, not a performance slogan. public means a CDN or browser may store the response for reuse across users. private means only the end user's browser should keep it. Authenticated or personalized HTML that also sets cookies should be private or no-store — not public. Static assets can stay public with long max-age. RoastMyOpsec inspects Cache-Control versus Set-Cookie on the primary response. It does not poison caches or fetch other users' pages.

The practical difference

A shared cache that stores a page with someone else's session cookie header — or a body that includes their name — will serve that mix to the next visitor. That is the failure mode, not 'the CDN is too fast.'

private still allows the browser to cache. no-store is for responses you do not want replayed from disk at all, such as account dashboards after logout is a concern.

How to choose based on the response

Separate route classes. Marketing HTML can often be public if it is the same for everyone and does not Set-Cookie a session. App HTML that varies by account should be private or no-store. JS/CSS/images with content hashes can be public and immutable.

ResponseCache-ControlCookiesTakeaway
Public marketing HTMLpublic, short max-age or s-maxageNone, or non-session prefs onlyFine when the body is identical for all
Logged-in HTMLprivate, no-store, or no-cacheSession cookies likelyNever public on a shared cache
Hashed static assetspublic, max-age long, immutableNoneThis is where CDNs earn rent
API JSON with PIIprivate or no-storeIf used, still not publicDo not let intermediaries reuse bodies

When public still fails the roast

public on a document that also sends Set-Cookie is the classic miss. Even if the body looks generic, caches can store the cookie semantics poorly and browsers can get confused about what is shareable.

Fix at the origin and at the CDN: explicit rules per path prefix, not one global 'cache everything' toggle.

Common mistakes

The first mistake is copying a static-site Cache-Control onto an app shell.

The second mistake is Vary: Cookie without understanding you just exploded cache keys — or omitted Vary and shared the wrong body.

The third mistake is purging the CDN once and leaving the origin header wrong.

Free audit the URL you own

RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.

Free audit now

FAQ

Is Cache-Control public a vulnerability?
Not by itself. It is a miss when the response is personalized or paired with session cookies. Public is appropriate for identical, unauthenticated assets.
Should I use private or no-store for dashboards?
private allows the user's browser to reuse the page. no-store is stricter when you do not want that file on disk. Many account pages use private, no-cache plus a solid logout.
How does RoastMyOpsec grade caching?
Header inspection on the primary response: Cache-Control versus Set-Cookie combinations. No cache-poisoning tests.

Sources

Related guides