Cookie without SameSite attribute

A cookie is set without a SameSite attribute, or with SameSite=None but no Secure flag. Depending on the browser, it may be attached to cross-site requests, which is what cross-site request forgery relies on.

Do this: Add SameSite=Lax, or SameSite=None with Secure if cross-site. The cookie rides along on cross-site requests, which is what makes CSRF possible in the first place.
PassAll cookies declare a SameSite attribute.
LowOne or more cookies lack a SameSite attribute or use SameSite=None without Secure.

The fix, in one snippet

Example to adapt Set-Cookie
Set-Cookie: session=…; SameSite=Lax; Secure; HttpOnly
# cross-site embeds need: SameSite=None; Secure

Illustrative values. Change the paths, hostnames and options to match your own site before using it.

The sections below explain what is tested, why it matters and the alternatives.

What we test

Scan.now parses the Set-Cookie headers on the response to / and reports each cookie's SameSite value. The check fails at low severity for any cookie with no SameSite attribute, and it also flags SameSite=None without Secure, a combination that Chrome and Firefox reject outright, so the cookie is silently never set. Lax and Strict pass; None; Secure passes with a note, since it is the correct value for a cookie that must work inside cross-site iframes but should not be used for a primary session. Behaviour for a missing attribute differs by browser: Chromium-based browsers have treated it as Lax since Chrome 80 (2020), with a two-minute grace period for top-level POST requests, while Firefox and Safari do not apply that default and still send such cookies on cross-site requests. An explicit attribute removes the difference.

Why it matters

Cross-site request forgery works because the browser attaches your cookies to a request regardless of which page made it. A form on evil.example that auto-submits to https://bank.example/transfer arrives with the victim's session cookie and looks legitimate. SameSite=Lax stops the cookie from being sent on cross-site POSTs, iframe loads and image requests while still sending it when the user follows a normal link to your site, which is why it is the sensible default for a session cookie. Strict also withholds the cookie on link navigation, which is stronger but means a user arriving from an email link sees a logged-out page. SameSite also blunts some clickjacking and cross-site-leak techniques. It is a second layer, not a replacement for anti-CSRF tokens: requests from a sibling subdomain are same-site and still carry the cookie, and GET requests that change state are unaffected. The cookie flags guide covers the trade-offs.

How to fix it

Set SameSite=Lax on session cookies, Strict where the extra friction is acceptable, and None; Secure only for cookies that legitimately need to travel cross-site:

Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

PHP 7.3+ (php.ini):

session.cookie_samesite = Lax

Express with express-session:

app.use(session({ cookie: { sameSite: 'lax', secure: true, httpOnly: true }, /* ... */ }));

Django: SESSION_COOKIE_SAMESITE = 'Lax' (the default) and CSRF_COOKIE_SAMESITE = 'Lax'. ASP.NET Core: options.Cookie.SameSite = SameSiteMode.Lax. Rails sets Lax by default since 6.1. At the proxy, nginx 1.19.3+:

proxy_cookie_flags ~ samesite=lax secure httponly;

Apache: Header edit Set-Cookie ^(.*)$ "$1; SameSite=Lax". For an embedded widget that must keep a cookie inside another site's iframe, use SameSite=None; Secure and treat that cookie as low-trust. Keep your CSRF tokens either way.

Where this fits

Cookie without SameSite attribute is check 3 of 4 that the website vulnerability scanner runs under cookie security, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.

Fix this one first

Above it in the same category sits Cookie without Secure flag (medium), where a cookie is set without the Secure attribute, so the browser will also send it over plain HTTP. An attacker who has that does not need this, so it is the better use of the same hour.

What fixing this still leaves open

Cookie without SameSite attribute closes one route in. The next one down is Cookie name prefixes (__Host- / __Secure-), where session cookies do not use the __Host- or __Secure- name prefixes, so a subdomain, an HTTP origin or a lookalike path could plant a cookie that your site accepts as its own.

Found in the same scan

The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.

Prompt for an AI Hand this check to an assistant Sign in to copy it
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.

Finding: Cookie without SameSite attribute (low severity)
Scanner check id: cookie-samesite
18 more lines, including the evidence and the exact fix

The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.

Sign in with Google

Signing in is free and takes one click. We store your email address and nothing else.

References

  1. MDN: SameSite cookies
  2. web.dev: SameSite cookies explained
  3. OWASP Cross-Site Request Forgery Prevention Cheat Sheet

Related guides