Website Spec
Security Required Updated 2026-05-29

Cookie attributes — Secure, HttpOnly, SameSite

Every cookie should be Secure, HttpOnly where possible, and have an explicit SameSite. Use __Host- and __Secure- prefixes for session cookies.

What it is

Cookies carry session state, authentication, and preferences. The Set-Cookie response header has a handful of attributes that decide how much the cookie can be abused if something goes wrong. Setting them correctly is one of the cheapest, highest-impact security wins on any site.

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

The attributes below are specified in RFC 6265bis (the in-progress update to RFC 6265).

Why it matters

A cookie without Secure can leak over plain HTTP. A cookie without HttpOnly can be read by any JavaScript that runs in the page — including XSS payloads. A cookie without SameSite is attached to cross-site requests, which is exactly what CSRF needs. Modern browsers default SameSite to Lax when not set, but relying on the default leaves older clients and edge cases unprotected.

How to implement

Set these attributes on every cookie unless you have a specific reason not to.

  • Secure — sent only over HTTPS. Mandatory on any cookie that carries identity. Required for SameSite=None.
  • HttpOnly — not exposed to document.cookie. Use on every session cookie. Skip it on cookies your JavaScript genuinely needs to read (preferences, A/B test bucket).
  • SameSite=Lax — sent on top-level navigations to your site but not on cross-site iframes, images, or fetch. Sensible default for session cookies.
  • SameSite=Strict — sent only on requests originating from your own site. Strongest CSRF defence; breaks the common pattern of arriving via an external link while already logged in.
  • SameSite=None; Secure — required for cross-site cookies (third-party widgets, SSO, embedded checkouts). Use sparingly.

Two browser-enforced prefixes raise the bar further:

  • __Secure- — the cookie name must start with __Secure-, and the browser only accepts the cookie if it has the Secure attribute.
  • __Host- — name starts with __Host-, the cookie must be Secure, must have Path=/, and must not have a Domain attribute. Pins the cookie to the exact host.

Use __Host- for session cookies whenever you can. It blocks subdomain takeover from rewriting the session cookie.

Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: __Secure-prefs=dark; Path=/; Secure; SameSite=Lax; Max-Age=31536000

Always set an explicit Path, Max-Age or Expires, and a sensible value length. Avoid Domain=example.com unless you really need the cookie on subdomains.

Common mistakes

  • No Secure. A single HTTP request leaks the cookie.
  • No HttpOnly on session cookies. Any XSS becomes an account takeover.
  • SameSite=None without Secure. Modern browsers reject the cookie outright.
  • Putting __Host- on a cookie with Domain set. Browser ignores it.
  • Sharing one cookie across many subdomains by default. Set Domain only when you actually need it.

Verification

  • DevTools → Application → Cookies. Each row shows the attributes. Confirm Secure, HttpOnly, and SameSite on every session cookie.
  • curl -sI https://example.com | grep -i set-cookie.
  • Try setting __Host-foo=1; Path=/ from a page without Secure — the browser should refuse.
  • Audit cookies served by third parties; their defaults are not your defaults.

Related topics

Sources & further reading

Search
esc close navigate open