All guides · Security

Cookie Security: Secure, HttpOnly and SameSite

Cookies often carry the most valuable thing on your site: the session that keeps a visitor logged in. Anyone who obtains a session cookie can act as that user. Three attributes on the Set-Cookie header decide how well that cookie is protected.

Why it matters

Attribute Protects against
Secure the cookie being sent over plain HTTP, where anyone on the network path can read it
HttpOnly JavaScript reading the cookie, so a cross-site scripting bug cannot simply copy the session out
SameSite the browser attaching the cookie to requests started by other sites, the basis of cross-site request forgery (CSRF)

None of these replace other defenses: you still need HTTPS everywhere, output escaping and CSRF protection for state-changing requests. They limit the damage when something else goes wrong.

What we check

We look at every Set-Cookie header your server sends when we load the scanned page.

Check Passes when
Cookie flags every cookie has Secure (on HTTPS sites), HttpOnly and a SameSite attribute
  • A cookie without Secure on an HTTPS site fails the check.
  • A cookie missing only HttpOnly or SameSite is reported as “needs attention”.
  • A page that sets no cookies passes.

The report lists each affected cookie by name and the attributes it is missing. We only see cookies set in that one response. Cookies set later, by JavaScript or by other pages such as the login form, are not included.

How to fix

For a session cookie, the target looks like this:

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

Choosing SameSite

  • Lax: the cookie is sent on normal top-level navigation from other sites (following a link) but not on cross-site form posts, frames or background requests. A good default for session cookies.
  • Strict: never sent on requests started by another site, not even links. Visitors arriving from an email or search result will appear logged out on the first page. Good for high-value actions on a separate cookie.
  • None: always sent, for cookies that must work in cross-site contexts such as embedded widgets or third-party sign-in. Browsers require Secure together with SameSite=None.

Some browsers treat a cookie without SameSite as Lax, but not all do. Set it explicitly.

Use the __Host- prefix for session cookies. A cookie named __Host-session is only accepted by browsers if it has Secure, Path=/ and no Domain attribute. That stops subdomains from overwriting it.

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

In your application

Set the attributes where the cookie is created. Examples:

Node.js (Express)

res.cookie('session', value, { secure: true, httpOnly: true, sameSite: 'lax' });

PHP (php.ini, for the built-in session cookie)

session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = "Lax"

Django (settings.py)

SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_SECURE = True

At the proxy

If you cannot change the application, Nginx 1.19.3 and newer can add flags to cookies from a proxied backend:

proxy_cookie_flags ~ secure httponly samesite=lax;

Fixing it in the application is better, because the application knows which cookies need which settings.

Cookies that need JavaScript access

Some cookies are meant to be read by your own scripts, for example a consent choice or a CSRF token that a script copies into a request header. Those cannot be HttpOnly, and our check will list them. That is expected: make sure they contain nothing sensitive, keep Secure and SameSite on them, and never store a session identifier in a cookie scripts can read.

Third-party cookies

Cookies used by analytics or ad services are set by their scripts or their own servers, not by your page response, so this check does not see them. Review them through your consent tool and the vendor’s documentation.

Further reading: MDN: Using HTTP cookies and OWASP: Session Management Cheat Sheet.

Last updated October 24, 2026