The short answer

Set session and authentication cookies like this:

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

Use Secure on every cookie of an HTTPS site, HttpOnly on every cookie that page scripts do not need to read, and SameSite=Lax or Strict unless the cookie must work inside other sites.

How cookies leak

How a session cookie is stolen without Secure and HttpOnly, and kept safe with them Top, without the flags: the site sets a session cookie with no Secure or HttpOnly flag. When the visitor follows a plain http link the browser sends the cookie unencrypted, and an injected script can also read it from document.cookie, so an attacker can copy it and take over the account. Bottom, with Secure and HttpOnly: the browser only sends the cookie over HTTPS and keeps it out of reach of scripts, so neither path exposes it. No Secure, no HttpOnly Site sets cookie session=abc123 Two ways out Sent on an http:// request Read via document.cookie Attacker copies it Network or injected script Account taken over Cookie replayed Session cookie readable on the network Any injected script can steal it Secure; HttpOnly; SameSite=Lax Site sets cookie Secure; HttpOnly Browser guards it HTTPS only, hidden from JS Attacker Sees nothing to copy Session stays private Only your site gets it Never sent over plain HTTP Scripts cannot read it How a session cookie is stolen without Secure and HttpOnly, and kept safe with them Top, without the flags: the site sets a session cookie with no Secure or HttpOnly flag. When the visitor follows a plain http link the browser sends the cookie unencrypted, and an injected script can also read it from document.cookie, so an attacker can copy it and take over the account. Bottom, with Secure and HttpOnly: the browser only sends the cookie over HTTPS and keeps it out of reach of scripts, so neither path exposes it. No Secure, no HttpOnly Site sets cookie session=abc123 Two ways out Sent on an http:// request Read via document.cookie Attacker copies it Network or injected script Account taken over Cookie replayed Session cookie readable on the network Any injected script can steal it Secure; HttpOnly; SameSite=Lax Site sets cookie Secure; HttpOnly Browser guards it HTTPS only, hidden from JS Attacker Sees nothing to copy Session stays private Only your site gets it Never sent over plain HTTP Scripts cannot read it
A session cookie works like a password that is sent with every request. The flags decide where it may go.

How DNS Panopticon detects it

Security Posture reads the Set-Cookie headers your homepage sends and checks each cookie’s flags. Cookies whose names look like sessions or sign-ins (containing sess, sid, auth, token, login, jwt or remember) are held to the HttpOnly rule. The result appears on the Website Application Security card.

FindingSeverityWhen it appears
Cookies without the Secure flagMediumThe site uses HTTPS but sets cookies without Secure, so the browser would also send them over plain http. Up to four names are listed.
Session cookies readable by scriptsLowA cookie with a session-like name has no HttpOnly flag.
Cookies are flagged safelyPassEvery cookie on the homepage has the expected flags.

Only cookies set by the homepage response are seen. Cookies set after sign-in, by JavaScript, or on other pages are not, so check them in the browser too. SameSite is explained here but not graded.

How to check it yourself

Command or toolWhat to look for
curl -sI https://example.comEach set-cookie line and whether it ends with Secure, HttpOnly and a SameSite value.
curl -s -o /dev/null -D - https://example.com/loginThe same for a sign-in page (on Windows, use -o NUL).

In Chrome or Edge, open developer tools, then Application → Cookies; in Firefox, Storage → Cookies. The table has columns for Secure, HttpOnly and SameSite for every cookie the site has set, including ones set after you sign in.

What each flag does

AttributeWhat it doesWhat goes wrong without it
SecureThe browser only sends the cookie over HTTPS.One http:// request, such as an old link or an image, sends the cookie in the clear.
HttpOnlyPage scripts cannot read the cookie through document.cookie.Any cross-site scripting bug lets an attacker copy the session.
SameSite=LaxSent on top-level navigation from other sites, not on their embedded requests or form posts.Other sites can make the browser send it with forged requests (CSRF).
SameSite=StrictNever sent on requests started by another site.As above; Strict also means users arriving from a link are not signed in on that first page.
SameSite=NoneSent everywhere; must be combined with Secure.Needed only for cookies used inside other sites, such as embedded widgets.
__Host- prefixA name starting with __Host- requires Secure, Path=/ and no Domain.Without it, a subdomain could set a cookie that overrides yours.

Current browsers treat a cookie with no SameSite attribute as Lax, but setting it explicitly keeps behaviour the same in every browser.

Why it matters

  • Session hijacking. A stolen session cookie lets an attacker use the account without a password or MFA, until the session expires.
  • Cross-site scripting. Most XSS attacks aim for the session cookie first. HttpOnly takes that prize away, even though the script can still act inside the page.
  • Insecure links. Even an HTTPS-only site can be reached over http:// by a typed address or an old link. Without Secure, the cookie goes along. HSTS helps, but Secure is the direct fix.

How to fix it

Cookies are set by your application or platform, so the fix is usually a configuration setting rather than web server code:

PlatformSetting
PHPIn php.ini: session.cookie_secure = 1, session.cookie_httponly = 1, session.cookie_samesite = "Lax"
ASP.NET CoreCookieSecurePolicy.Always, HttpOnly = true and SameSite = SameSiteMode.Lax in the cookie or session options
ASP.NET (web.config)<httpCookies requireSSL="true" httpOnlyCookies="true" sameSite="Lax" /> under system.web
Expresscookie: { secure: true, httpOnly: true, sameSite: 'lax' } in express-session
DjangoSESSION_COOKIE_SECURE = True, CSRF_COOKIE_SECURE = True; HttpOnly and Lax are the defaults
nginx (proxy)proxy_cookie_flags ~ secure httponly samesite=lax; (nginx 1.19.3 and later) to add flags to an upstream app’s cookies
  1. Start with session and sign-in cookies, then the rest.
  2. Leave HttpOnly off only for cookies your own JavaScript must read, such as a UI preference or a CSRF token read by a script. Never for the session.
  3. Third-party cookies from analytics or chat tools are set by those vendors’ scripts; check their settings, or consider whether you need them.
  4. Sign everyone out after changing session cookie settings if you suspect cookies were exposed, so old sessions stop working.

FAQ

Does HttpOnly stop cross-site scripting?

No. An injected script can still act inside the page as the user. HttpOnly only stops it from copying the session cookie to use elsewhere. A Content-Security-Policy is what limits injected scripts.

Our analytics cookie (_ga) is flagged. Should it be HttpOnly?

No: the analytics script needs to read it. DNS Panopticon only applies the HttpOnly rule to cookies whose names look like sessions or sign-ins. All cookies on an HTTPS site should still have Secure.

Should I use SameSite=Strict?

For highly sensitive apps, such as banking or admin consoles, Strict is a good choice. For most sites, Lax balances protection with keeping users signed in when they follow a link to you.

Can I set these flags in a CDN instead of the app?

Sometimes. Some CDNs and reverse proxies can rewrite Set-Cookie headers, as nginx’s proxy_cookie_flags does. Fixing it in the application is more reliable because it covers every response.

Sources and further reading