Complete Guide to Cookie Security Flags | Secure / HttpOnly / SameSite / __Host-
Cookies are the most commonly used mechanism for session management in web applications, but improper configuration can lead to attacks such as session hijacking, CSRF (cross-site request forgery), and token theft via XSS. This article explains the meaning of four essential flags (Secure / HttpOnly / SameSite / __Host- prefix) that should be applied to cookies and clarifies common pitfalls in implementation.
Set-Cookie Header Structure
When the server sets a Cookie in the browser, it returns a header like the following in the HTTP response.
Set-Cookie: session_id=abc123; Path=/; Domain=example.com; Expires=Wed, 22 Apr 2026 10:00:00 GMT; Secure; HttpOnly; SameSite=Lax
There are multiple attributes separated by semicolons, which can be broadly divided into the following two types.
- Scope attributes: Path / Domain / Expires / Max-Age — Determine when and where a cookie is sent
- Security attributes: Secure / HttpOnly / SameSite — Restrict transmission and access
Secure — Send only over HTTPS
A cookie with the Secure attribute is sent to the server by the browser only over HTTPS connections. Without it, when a victim accesses the site via http://, the cookie flows in plaintext, and session IDs can be stolen via Man-in-the-Middle attacks.
Golden rule: Always attach it to authentication cookies. In local development, localhost allows Secure cookies even without HTTPS, but as long as you assume production HTTPS, there's no issue.
HttpOnly — Inaccessible from JavaScript
adding HttpOnly prevents reading via document.cookie. This prevents JavaScript injected by XSS attacks from stealing cookies.
Since XSS remains a possible vulnerability, consider the HttpOnly flag essential for session cookies. If your JavaScript code needs to read cookie values (e.g., CSRF tokens), the standard approach is to either create a separate read-only cookie or pass the value via <meta> tags.
SameSite — Control transmission in cross-site requests
The SameSite attribute is core to CSRF protection. The values are the following three:
| Value | Behavior | CSRF Protection |
|---|---|---|
Strict | Do not send to cross-site requests at all (even when coming from external links) | Most powerful |
Lax (default) | Send only on top-level GET navigation (link clicks OK, POST forms NG) | Strong |
None | Sent with all cross-site requests (Secure required) | None |
Modern browsers since 2020 treat unspecified SameSite as Lax, so you get minimal CSRF protection even without explicit specification. However, it's better to explicitly set it to clarify your intent.
When using SameSite=None with SSO integration or iframe embedding, you must also add Secure—this is a requirement of modern browsers. Cookies with SameSite=None but no Secure are rejected by browsers.
__Host- / __Secure- Prefixes
When a Cookie name starts with __Host-, the browser enforces the following three conditions.
Secureflag is required- must not include the
Domainattribute (i.e., only the exact host that sent the request) Path=/is required
These provide strong guarantees: "cannot be overridden from other subdomains" and "cookies cannot be placed by Host header spoofing." For session cookies, it is most robust to add a prefix like __Host-session.
The other __Secure- prefix enforces only the mandatory Secure flag (no Domain / Path restrictions).
4096 byte limit
The Cookie value is recommended to be a total of 4096 bytes according to RFC 6265. If you put large JSON or arrays in a Cookie and exceed this limit, the browser may silently truncate them. The best practice is to store large data in server-side sessions and put only the session ID in the Cookie.
Implementation Example: Authentication Session Cookie
A properly configured authentication Cookie looks like the following:
Set-Cookie: __Host-session=eyJ0eXAi...; Path=/; Max-Age=3600; Secure; HttpOnly; SameSite=Lax
__Host-: Prevents subdomain pollution and host spoofingPath=/: Accessible across the entire siteMax-Age=3600: Expires in 1 hourSecure: Sent only over HTTPSHttpOnly: Not accessible from JavaScriptSameSite=Lax: Not sent for cross-site POST requests (CSRF protection)
PHP (Laravel) example
// config/session.php
return [
'secure' => true, // Secure フラグ
'http_only' => true, // HttpOnly フラグ
'same_site' => 'lax', // SameSite=Lax
'path' => '/',
'cookie' => '__Host-session',
];
Node.js (Express) example
const session = require('express-session');
app.use(session({
name: '__Host-session',
secret: process.env.SESSION_SECRET,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'lax',
path: '/',
maxAge: 3600 * 1000,
},
}));
How to check Cookie settings on an existing site
You can instantly verify whether cookies on your site or third-party sites are set correctly using the DevLab Cookie inspection tool. Simply enter a URL, and the tool analyzes all returned Set-Cookie headers and displays diagnostics like the following.
- Presence of Secure / HttpOnly / SameSite for each cookie
- Violations such as SameSite=None without Secure
- Consistency of __Host- Prefix
- 4096 byte overrun warning
- Overall summary (Secure rate / HttpOnly rate / SameSite distribution)
Summary
Cookie security flags should not be set arbitrarily, but rather configured based on understanding attack scenarios and appropriate countermeasures. At minimum, production authentication session Cookies should include Secure + HttpOnly + SameSite + __Host- prefix + short Max-Age. For reviewing settings on existing sites, we recommend using the Cookie inspection tool.