Web Security

SameSite Cookies: The Quiet Default That Killed a Lot of CSRF

June 19, 2026 7 min read Haven Team

Around 2020, browsers changed a default almost nobody noticed — and a whole class of cross-site request forgery attacks quietly stopped working. The mechanism is a single cookie attribute called SameSite. Understanding it, along with the other flags on a Set-Cookie line, is the difference between a session that resists hijacking and one that hands itself out.


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.

Why Lax, not Strict, became the default

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:

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.

A sensible default for a session cookie

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.

Try Haven free for 15 days

Encrypted email and chat in one app. No credit card required.

Get Started →