Skip to content

SameSite attribute set to Lax instead of Strict

CWE-1275CWE-352OWASP A07:2025Updated October 2, 20265 min read

SameSite=Lax still sends the session cookie when a user navigates to your site through an external link. That blocks most CSRF attacks, but not those that work through ordinary navigation, and it does not help with endpoints that change state on a GET request. For sensitive applications, Strict is the safer choice.

Since Chrome and Edge adopted SameSite=Lax as the default for cookies without the attribute, a large share of classic CSRF attacks has disappeared on its own; Firefox and Safari do not apply that default. That success makes it tempting to treat the setting as settled. One specific category remains, however, which Lax deliberately lets through. This article explains which one, and when the step to Strict is worth making.

What does the SameSite attribute do?

The SameSite attribute determines whether the browser sends a cookie with a request that originates from another site. There are three values. Strict sends the cookie only with requests arising within your own site. Lax does the same, with one exception: on top-level navigation using a safe method, in short when the user clicks a link and thereby goes to your site, the cookie does travel. None removes the restriction altogether.

That single exception in Lax exists for a practical reason. Without it, everyone arriving at your site through an email, a search result or a shared link would be greeted by a login screen while holding a perfectly valid session. That is annoying enough to make Lax the common compromise.

So it is not a mistake but a trade-off. Compare it with a door that is locked, except for whoever rings the bell and is let in. For most buildings that is fine. For a vault it is not.

What does Lax still let through?

The difference becomes concrete with endpoints that change something and are reachable through navigation.

Vulnerable:

Set-Cookie: sid=8f42c19ade7b3f5c; HttpOnly; Secure; SameSite=Lax; Path=/

This cookie is reasonably protected, and a classic CSRF attack with an auto-submitting POST form from a foreign site no longer works: on a cross-site POST the cookie stays at home. But if the application contains an action that runs through a GET, the picture changes:

<!-- On the attacker's page; one click by the victim is enough -->
<a href="https://portal.example/subscription/cancel?confirm=yes">
  View your invoice
</a>

This is top-level navigation with a safe method, so the browser sends the session cookie along quite normally. The action is carried out on behalf of the logged-in user. The same applies to an attacker who forces navigation with JavaScript through window.open or a <form method="GET">. Chrome and Edge also make a temporary exception for cookies that carry no SameSite attribute and are Lax only by default: for two minutes after such a cookie is set, it still travels with a cross-site POST, which yields a small but real window.

Safe:

Set-Cookie: __Host-sid=8f42c19ade7b3f5c; HttpOnly; Secure; SameSite=Strict; Path=/

With Strict the cookie travels with no externally initiated request at all, not even when following a link. The attack above then produces a logged-out session rather than a cancelled subscription.

If you want Strict without stranding users who arrive through external links, the usual pattern is two cookies: a short-lived Lax cookie whose only job is to signal that a session exists, and the actual session cookie on Strict. The landing page then sees that the user is known and forwards them through internal navigation, after which the Strict cookie does travel.

Remember that “same site” is not the same as “same origin”. All subdomains of your organisation count as the same site, so a vulnerability on a marketing page or test environment falls outside SameSite’s protection. That is one of the reasons CSRF tokens remain necessary even with Strict.

What is the impact of SameSite set to Lax?

On its own this is a hardening finding with a low severity. Lax blocks most attack patterns, and many applications also have CSRF tokens, which keeps the residual risk small.

The significance arises in combination with other choices. If endpoints exist that change state through a GET request, such as a cancellation, a confirmation, an activation or a deletion, then protection is absent for exactly those endpoints. And that kind of route often appears by accident, for instance because a confirmation link in an email is by nature a GET.

A second factor is the presence of subdomains. Because they count as the same site, SameSite offers no protection in any variant against an attack carried out from one of your own subdomains. Organisations with many subdomains, test environments or supplier-managed pages therefore get less from this attribute than it appears.

How do you check your SameSite setting?

The value of the attribute is read directly from the Set-Cookie header. More interesting is what that value means in this specific application, and that calls for an inventory of the endpoints.

A tester looks for routes that change something but are reachable through a GET: confirmation links, activation URLs, cancellations, and admin functions implemented as a link. For each of those they check whether a CSRF token is required. They also check whether the attribute is applied consistently to all authentication cookies, whether any cookies carry SameSite=None without needing it, and whether subdomains exist that could serve as a stepping stone. AssistSec judges this not as an isolated setting but as part of overall CSRF resilience, because the question is not which value is set but whether an attacker can still force an action in practice.

How do you set SameSite safely?

  • Use SameSite=Strict for session cookies of applications with sensitive or irreversible actions.
  • Apply a two-cookie pattern if you want Strict without hindering users arriving through external links.
  • Keep using CSRF tokens on every state-changing action; SameSite is an addition, not a replacement.
  • Never perform a change on a GET request, not even for confirmation links from emails.
  • Set SameSite=None only on cookies demonstrably needed in a cross-site context, always together with Secure.
  • Treat subdomains as part of your attack surface, because SameSite regards them as the same site.
  • Check the Sec-Fetch-Site header on sensitive actions as an extra layer, with Origin and Referer as a fallback.
  • Record the chosen value in your session configuration, so new cookies inherit it automatically.

Sources

Frequently asked questions

What exactly is the difference between Lax and Strict?

With Strict the cookie never travels when the request originates from another site, not even when following an ordinary link. With Lax it does travel on top-level navigation with a safe method, so when someone clicks a link. That difference is precisely where the risk sits.

Why do so many applications choose Lax then?

For practical reasons. With Strict, a user arriving through a link in an email or from a search engine lands on the login screen even though they have a valid session. That is felt as an annoyance. Lax is a compromise between usability and security, not maximum protection.

Is SameSite enough to prevent CSRF?

No, and that is the key message. SameSite is a strong base layer but does not cover every case: subdomains count as the same site, older browsers do not apply it, and with Lax navigation-based attacks remain possible. Always combine it with CSRF tokens on state-changing actions.

What does SameSite=None do?

That value disables the protection entirely and is meant only for cookies genuinely needed in a cross-site context, for example with an embedded widget. Chrome, Edge and Firefox accept it only in combination with Secure. Never use it for the session cookie of an ordinary application.

Related articles

Press / to search · Esc