Skip to content

Complete Guide to Cookie Security Flags | Secure / HttpOnly / SameSite / __Host-

Category: Web Security

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.

  1. Scope attributes: Path / Domain / Expires / Max-Age — Determine when and where a cookie is sent
  2. 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:

ValueBehaviorCSRF Protection
StrictDo 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
NoneSent 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.

  • Secure flag is required
  • must not include the Domain attribute (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 spoofing
  • Path=/: Accessible across the entire site
  • Max-Age=3600: Expires in 1 hour
  • Secure: Sent only over HTTPS
  • HttpOnly: Not accessible from JavaScript
  • SameSite=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.

❓ Frequently Asked Questions

When should I use SameSite=Lax instead of Strict?
Lax is the default answer for a session cookie that keeps someone logged in. With Strict, the first request after following a link from another site carries no cookie, so a logged-in user is shown as logged out. Reserve Strict for cookies that guard actions which must never be triggered from another origin, such as confirming a payment or changing a password.
Does HttpOnly prevent XSS?
No. HttpOnly only stops an attacker reading the token through document.cookie once XSS has already succeeded. It does not stop the injection, so the attacker can simply issue requests from the page instead of stealing anything. Output escaping and a Content-Security-Policy are the actual defence; HttpOnly narrows the damage by one step.
What does the __Host- prefix actually guarantee?
The browser enforces Secure, Path=/ and the absence of a Domain attribute, rejecting any Set-Cookie that fails those conditions. The payoff is that a subdomain can no longer overwrite the cookie: because Domain cannot be set, user.example.com cannot replace a cookie belonging to example.com, which structurally blocks session fixation from a hijacked subdomain.