Skip to content

SameSite attribute set to Lax instead of Strict

CWE-1275CWE-352OWASP A07:2021Updated September 4, 20264 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 browsers adopted SameSite=Lax as their default, a large share of classic CSRF attacks has disappeared on its own. 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">. Browsers also apply an exception during the first minutes after a cookie is set, where Lax behaves more leniently, 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 Origin and Referer headers on sensitive actions as an extra layer.
  • 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. Browsers accept it only in combination with Secure. Never use it for the session cookie of an ordinary application.

Related articles

Press / to search · Esc