Cookies are how the web remembers you. When you log in, the server sends a Set-Cookie header; your browser stores it and attaches it to every subsequent request to that site. That automatic attachment is the convenience — and the vulnerability. The browser sends the cookie even when the request was triggered by another website, which is exactly the gap that cross-site request forgery (CSRF) exploits.
The cookie attributes — SameSite, Secure, HttpOnly, and the special name prefixes — are the controls that decide when a cookie travels and who can touch it. Most of them cost one word to set and prevent entire attack categories.
What SameSite actually controls
SameSite tells the browser whether to attach a cookie on requests that originate from a different site. "Site" here means the registrable domain (eTLD+1), so app.example.com and www.example.com count as the same site, while example.com and attacker.com do not. There are three values:
| Value | Cookie sent on cross-site requests? |
|---|---|
| Strict | Never. Not even when a user clicks a link from another site to yours. Maximum protection, but a logged-in user following an external link arrives logged out until they navigate again. |
| Lax | Only on top-level navigations using safe methods (clicking a link, a GET). Not on cross-site POSTs, iframes, or background fetches. This is the modern default. |
| None | Always — but the cookie must also be marked Secure, or browsers reject it. Use only when cross-site sending is genuinely required. |
The pivotal change: major browsers now treat a cookie with no SameSite attribute as if it were Lax. Before that, the default was effectively None — cookies went everywhere. Flipping the default to Lax meant a malicious site could no longer auto-submit a cross-site POST that carried your session cookie, neutering the classic CSRF payload without developers changing a line.
Strict would break ordinary navigation — clicking a link to a site you're logged into would show you as logged out. Lax was the compromise: block the dangerous cross-site POSTs and background requests, but still send the cookie when a human deliberately navigates to the site.
The flags that ride alongside it
SameSite is one of a small family. The others matter just as much:
- Secure — the cookie is only ever sent over HTTPS, never plain HTTP. This stops a network attacker on an open Wi-Fi network from reading it in transit. It is also a hard requirement for
SameSite=None. - HttpOnly — JavaScript cannot read the cookie via
document.cookie. This is your defense against cross-site scripting (XSS) stealing a session: even if an attacker injects script, an HttpOnly session cookie stays out of reach. - Path and Domain — scope which URLs and hosts receive the cookie. Narrower is safer; a permissive
Domainshares the cookie with every subdomain.
The __Host- and __Secure- prefixes
Two cookie-name prefixes act as enforced contracts. A cookie named __Secure-session is rejected by the browser unless it carries the Secure flag. A cookie named __Host-session is rejected unless it is Secure, has no Domain attribute (so it cannot be shared with subdomains), and has Path=/. These prefixes prevent a weaker cookie — perhaps set by a compromised subdomain — from overwriting the real one. The protection is baked into the name itself, so it cannot be silently dropped by a misconfiguration.
Where SameSite stops protecting you
SameSite is genuinely strong defense-in-depth, but treating it as your only CSRF protection is a mistake.
"Same site" is not "same origin." A vulnerability on any subdomain that shares your registrable domain is, as far as SameSite is concerned, you. Subdomain takeover or an XSS on a sibling host can issue requests SameSite considers same-site.
Other gaps: Lax still permits cross-site top-level GET requests, so any state-changing action reachable by GET remains exposed — a reason state changes should never be GETs. Older or niche browsers may not enforce the modern default. And SameSite does nothing against attacks that originate on your own site, like stored XSS. The durable advice has not changed: keep anti-CSRF tokens or the Origin/Sec-Fetch-Site header checks on state-changing endpoints, and layer SameSite on top.
Set-Cookie: __Host-session=…; Secure; HttpOnly; SameSite=Lax; Path=/ — HTTPS-only, invisible to JavaScript, not shared with subdomains, and immune to cross-site POST forgery. Reach for Strict on high-value cookies where the navigation trade-off is acceptable.
How Haven thinks about it
Haven's web app runs under a strict Content Security Policy and treats cookie hardening as table stakes — the secure flags are not optional toggles, they are the baseline. But the deeper principle is that no single browser default should be load-bearing. We bind sessions to device and key state so that even a cookie that escapes its intended scope does not become a usable credential on its own. If you found this useful, our pieces on XSS and clickjacking cover the neighboring corners of browser security.