privacy
Secure cookie attributes
MetricSpot inspects Set-Cookie headers for Secure, HttpOnly, and SameSite. Missing any of these widens the attack surface for cookie theft and CSRF.
What this check does
Reads every Set-Cookie response header and checks for three flags:
Secure— cookie only sent over HTTPS.HttpOnly— cookie not readable from JavaScript (blocks XSS-driven theft).SameSite=Lax|Strict|None— cross-site request behavior (blocks CSRF).
Passes when every cookie carrying authentication or session state has all three.
Why it matters
Cookies hold the keys to your users’ sessions. A cookie without these flags is one XSS vulnerability or one hostile Wi-Fi away from account takeover:
- No
Secure→ cookie travels over plain HTTP on the first request before HSTS kicks in. Sniffable on coffee-shop Wi-Fi. - No
HttpOnly→ any injected script (XSS, malicious npm dependency, hostile ad) can read the cookie viadocument.cookieand exfiltrate it. - No
SameSite→ cross-site request forgery (CSRF). An evil page can submit forms or trigger requests as your logged-in user.
Browsers have been tightening defaults: Chrome ships SameSite=Lax as the default now, but legacy code that explicitly sets cookies without flags still leaks.
How to fix it
Set every session/auth cookie with all three flags.
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=86400
Express / Node.js:
res.cookie("session", token, {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: 86400 * 1000,
path: "/",
});
Next.js (App Router with cookies()):
import { cookies } from "next/headers";
cookies().set({
name: "session",
value: token,
httpOnly: true,
secure: true,
sameSite: "lax",
path: "/",
maxAge: 86400,
});
Bun.serve():
return new Response("ok", {
headers: {
"Set-Cookie": `session=${token}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400`,
},
});
Django:
# settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = "Lax"
Rails:
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store,
key: "_app_session",
secure: Rails.env.production?,
httponly: true,
same_site: :lax
PHP / WordPress: in wp-config.php or before any output:
ini_set('session.cookie_secure', '1');
ini_set('session.cookie_httponly', '1');
ini_set('session.cookie_samesite', 'Lax');
Which SameSite value?
Strict— cookie never sent on cross-site requests. Maximum protection, but breaks the case where users follow a link to your site and arrive logged out. Good for high-stakes flows (admin, banking).Lax(default) — cookie sent on top-level navigations (clicking a link) but not on cross-site POSTs, iframes, or image requests. The right default for most sites.None— cookie sent on all cross-site requests. RequiresSecure. Use only when you genuinely need third-party context (embedded widgets, identity providers).
Cookie name prefixes add a second layer of enforcement:
__Secure-— browser refuses to set this cookie unlessSecureis also set.__Host-— browser refuses unlessSecure,Path=/, and noDomainattribute.
Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
Pair this rule with HTTPS, enable HSTS, and the referrer policy for a complete transport-security baseline.
Frequently asked questions
Will HttpOnly break my client-side code?
Only if you read the cookie from JavaScript. For session/auth cookies, you shouldn’t — the cookie should be opaque to the client and only used by the server. If you’re storing data the JS needs to read, that’s a different category of cookie (preferences, UI state) and HttpOnly doesn’t apply.
What about consent cookies and analytics?
Consent and analytics cookies often genuinely need to be JavaScript-readable. Set Secure and SameSite=Lax on them, but skip HttpOnly. The MetricSpot check tolerates this — it only warns when a session cookie is missing the flags.
Does this affect GDPR compliance directly?
Not the consent/legal-basis side, but the security side. GDPR Article 32 requires “appropriate technical measures” — missing cookie flags are routinely cited in supervisory authority decisions as a security failure. Pair with a cookie consent banner and privacy policy for the legal layer.
Sources
Last updated 2026-05-11