Article

The Secure Cookie Flag: What It Does and How to Set It

The Secure cookie flag tells the browser to send a cookie only over HTTPS, never plain HTTP, so a session token can't be exposed on the network. Add it to every cookie on an HTTPS site; a SameSite=None cookie without Secure is silently dropped by browsers.

By Paul Rudenko, Security ResearcherUpdated Jun 30, 20266 min read

The Secure attribute tells the browser to send a cookie only over an encrypted HTTPS connection, never over plain HTTP. Add it to every cookie on an HTTPS site — Set-Cookie: sid=…; Secure — so a session token can never be exposed on the network by an accidental or downgraded plain-HTTP request. There is no downside on a site that already serves HTTPS.

For the site owner (plain English)

In plain terms, the Secure flag is a note your site attaches to a cookie that says “only ever send this over the encrypted connection.” The cookie that keeps a user logged in is effectively their identity, so if it can travel unencrypted, someone on the same network could copy it and act as that user. That makes a missing Secure flag on a login or session cookie a genuine issue worth fixing soon — not something to shrug off. The good news is that it is one of the easiest fixes on the web: it is a single setting in whatever runs your site, and on a site that already uses HTTPS there is no downside. Ask your developer to enable secure cookies, then re-check with the tool below.

What the Secure flag does

A cookie marked Secure is attached by the browser only to requests sent over HTTPS. If the same site is ever reached over http:// — a typed URL, an old bookmark, a link in an email, or an attacker forcing a downgrade — the browser simply leaves the cookie out of that request. Without the flag, the cookie rides along in cleartext and anyone on the network path (shared Wi-Fi, a compromised router, an on-path attacker) can read it and replay the session.

This matters even for sites that redirect HTTP to HTTPS, because the first plaintext request is sent before the redirect is received — and that request already carries any non-Secure cookie. The flag closes that window.

On an HTTPS site, mark every cookie Secure, not just the session cookie. A non-sensitive cookie sent in the clear is still a request that can be observed and, combined with other leaks, can aid an attacker. There is no cost to setting it.

SameSite=None requires Secure

There is one case where a missing Secure flag is not just a weakness but a functional error: a cookie set with SameSite=None. Modern browsers require that any cookie which opts into cross-site sending also carries Secure. If it doesn't, the browser silently rejects the cookie entirely — so it likely isn't working at all. If you need a cross-site cookie, always pair the two: SameSite=None; Secure.

__Secure- and __Host- depend on it too

The cookie name prefixes build on Secure. A browser only accepts a __Secure- cookie if it carries the Secure flag, and a __Host- cookie must be Secure, set with Path=/, and carry no Domain. Claiming a prefix without meeting its rules is a real bug — the browser rejects the cookie, so the session can break. See the cookie security overview for how the prefixes fit together.

How to add the Secure flag

Set it wherever your application or framework issues the cookie:

# Raw header
Set-Cookie: sid=<token>; Secure; HttpOnly; SameSite=Lax; Path=/
// Express
res.cookie("sid", token, { secure: true, httpOnly: true, sameSite: "lax" });

# Django settings.py
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# Rails config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: "_app_session", secure: true

// PHP
setcookie("sid", $token, ["secure" => true, "httponly" => true, "samesite" => "Lax"]);

Behind a CDN or proxy that terminates TLS, make sure your framework still knows the original request was HTTPS (e.g. trust the X-Forwarded-Proto header) — otherwise it may decline to set Secure cookies because it thinks the connection is plain HTTP.

Check whether your cookies set the Secure flag — in seconds, free.

Run the cookie checker

A common gotcha

During local development over http://localhost, Secure cookies are not sent, which can make sessions appear broken. That is expected — gate the flag on your environment so it is on in staging and production (over HTTPS) and relaxed only for local HTTP development. Never ship the relaxed setting to production.

For the full picture, read the cookie security guide, and pair this with HttpOnly and SameSite.

Frequently asked questions

What does the Secure flag do on a cookie?

It tells the browser to attach the cookie only to requests sent over an encrypted HTTPS connection. You add it in the Set-Cookie header, for example Set-Cookie: sid=<token>; Secure; HttpOnly; SameSite=Lax; Path=/. If the site is later reached over plain HTTP — a typed URL, an old bookmark, or a forced downgrade — the browser omits the cookie from that request, so a session token can never be sent in cleartext where someone on the network path could read and replay it. This matters even on sites that redirect HTTP to HTTPS, because the first plaintext request goes out before the redirect arrives and would otherwise carry the cookie. On a site that already serves HTTPS there is no downside to marking every cookie Secure, so treat a missing Secure on a session cookie as a genuine fix.

Why is SameSite=None without Secure a problem?

Because modern browsers reject it. A cookie with SameSite=None is asking to be sent on cross-site requests, and the browser requires that any such cookie also carry the Secure flag. If Secure is missing, the browser silently discards the cookie entirely — it is never stored or sent — so the feature that relied on it, such as an embedded widget or a cross-site SSO flow, quietly breaks with no error message to point you at the cause. This makes it more of a functional bug than a classic security weakness, and it can be maddening to debug because the header looks present in your code but the cookie never appears in the browser. The fix is simple: always write the two together, as in Set-Cookie: sid=<token>; SameSite=None; Secure; HttpOnly; Path=/.

Should every cookie be Secure or just the session cookie?

Every cookie on an HTTPS site should be Secure. The session cookie is the highest-value target, and a login cookie without Secure is genuinely exploitable, so that one is the priority. But there is no benefit to letting any cookie travel in cleartext: a non-sensitive cookie sent over plain HTTP is still an observable request that can leak information — a locale, an analytics ID, a feature flag — and combined with other leaks it can aid an attacker. Since the flag costs nothing on a site that already serves HTTPS, set it on all cookies rather than trying to decide case by case which ones matter. The one place to relax it is local development over http://localhost, where Secure cookies aren't sent; gate the flag on environment and never ship the relaxed setting to production.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →