Understanding Cookie Prefixes
Cookie prefixes are special naming conventions for cookies that enable browsers to enforce security constraints. A cookie prefix is a string prepended to the cookie name that signals the browser to apply specific security rules.
Cookie prefixes were created to address a security gap: servers cannot reliably control whether cookies have certain security attributes. For example, a server can set a cookie with the Secure flag, but an attacker who controls JavaScript on the page could theoretically delete that cookie and create a non-secure version with the same name.
Cookie prefixes solve this by allowing servers to declare security requirements through the cookie name itself. Browsers then enforce these requirements automatically.
The "__Secure-" Prefix
The "__Secure-" prefix declares that a cookie must be transmitted securely.
When a cookie name starts with "__Secure-", the browser enforces that:
- The cookie must have the Secure attribute set
- The cookie must be set over HTTPS
- If the Secure flag is missing or the connection is not HTTPS, the browser rejects the cookie
How It Works
Set-Cookie: __Secure-session-id=abc123; Secure; HttpOnly; SameSite=Lax
If a server tries to set this cookie without the Secure attribute or over HTTP:
Set-Cookie: __Secure-session-id=abc123; HttpOnly // Missing Secure attribute
// Browser rejects this
The browser refuses to set the cookie because the "__Secure-" prefix requires the Secure attribute.
Use Cases
Use "__Secure-" for any cookie containing sensitive information that should only be transmitted securely:
- Authentication tokens
- Session IDs
- API keys
- Personal information
The prefix provides an extra layer of protection by ensuring that even if developers forget to include the Secure attribute, the browser enforces it.
The "__Host-" Prefix
The "__Host-" prefix is stricter and provides additional constraints.
When a cookie name starts with "__Host-", the browser enforces that:
- The cookie must have the Secure attribute set (like "__Secure-")
- The cookie must be set over HTTPS
- The cookie must NOT have a Domain attribute
- The Path must be "/" (root)
How It Works
Set-Cookie: __Host-session-id=abc123; Secure; Path=/; HttpOnly; SameSite=Strict
If a server tries to set "__Host-" cookie with these violations:
// Missing Secure attribute - REJECTED
Set-Cookie: __Host-session-id=abc123; Path=/
// Has Domain attribute - REJECTED
Set-Cookie: __Host-session-id=abc123; Secure; Domain=example.com; Path=/
// Path is not "/" - REJECTED
Set-Cookie: __Host-session-id=abc123; Secure; Path=/api
The browser rejects all of these because they violate the "__Host-" requirements.
Use Cases
Use "__Host-" for the most sensitive cookies where you want maximum security:
- Session tokens
- Authentication cookies
- Any cookie critical to security that should be host-only
The strict requirements of "__Host-" make it impossible to accidentally create an insecure cookie.
Comparing the Prefixes
| Feature | No Prefix | __Secure- | __Host- |
|---|---|---|---|
| Requires Secure | No | Yes | Yes |
| Requires HTTPS | No | Yes | Yes |
| Domain constraint | No | No | Yes (none) |
| Path constraint | No | No | Yes (/) |
| Flexibility | High | Medium | Low |
| Security | Lower | Higher | Highest |
Implementation Examples
Using __Secure-
// Node.js / Express
res.cookie('__Secure-auth-token', token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
domain: '.example.com' // Can specify domain with __Secure-
});
This cookie will only be set if:
- The Secure flag is present
- The connection is HTTPS
- If either is missing, the browser silently rejects the cookie
Using __Host-
// Node.js / Express
res.cookie('__Host-session-id', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'strict',
path: '/',
// No domain specified - required for __Host-
});
This cookie will only be set if:
- The Secure flag is present
- The connection is HTTPS
- No Domain attribute is specified
- The Path is exactly "/"
- If any requirement is violated, the browser rejects the cookie
Browser Support
Cookie prefixes are supported in all modern browsers:
- Chrome/Chromium: Fully supported
- Firefox: Fully supported
- Safari: Fully supported (starting with Safari 10.1)
- Edge: Fully supported
For older browsers that don't understand prefixes, the prefix is simply treated as part of the cookie name, and the cookie is set normally (without the additional security guarantees).
Security Benefits
Protection Against XSS
If an attacker injects JavaScript and tries to create a non-secure version of a prefixed cookie:
// Attacker-injected JavaScript tries to create non-secure cookie
document.cookie = "__Secure-auth-token=hacked; path=/";
// Browser rejects this because __Secure- requires Secure flag
The browser rejects this attempt because the prefixed cookie requires the Secure flag.
Protection Against Misconfiguration
Developers might forget to include the Secure flag:
// Accidental misconfiguration
res.cookie('__Host-session-id', token, {
httpOnly: true,
// Forgot secure: true
path: '/'
});
// Browser rejects this - enforces secure
The browser rejects this misconfiguration, ensuring security even if developers make mistakes.
Host-Only Cookies
With "__Host-", you ensure cookies cannot be accessed from subdomains:
example.com can access __Host-cookies
api.example.com CANNOT access __Host-cookies
This is useful for preventing cross-subdomain attacks where compromised subdomains might try to access parent domain's cookies.
Best Practices
1. Use __Host- for Session Cookies
Session cookies are critical to security. Use the "__Host-" prefix to maximize security:
res.cookie('__Host-session-id', sessionToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
path: '/',
maxAge: 24 * 60 * 60 * 1000 // 24 hours
});
2. Use __Secure- for Other Sensitive Cookies
For cookies that need Secure but also need to be shared across subdomains, use "__Secure-":
res.cookie('__Secure-auth-token', token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/',
domain: '.example.com' // Shared across subdomains
});
3. Document Your Cookie Strategy
Document which cookies use prefixes and why:
// Cookie strategy documentation
// Session token: __Host- prefix for maximum security
// Auth token: __Secure- prefix for security while allowing subdomain access
// User preference: __Secure- prefix for persistence and security
4. Test in All Browsers
Test that cookies are set correctly:
// In browser console
document.cookie // Check if cookies are visible (should be empty for HttpOnly)
// Or check Network tab in DevTools to see Set-Cookie headers
5. Combine with Other Security Measures
Cookie prefixes work best in combination with other security measures:
- HttpOnly: Prevent JavaScript access
- Secure: Ensure HTTPS transmission
- SameSite: Prevent CSRF attacks
- Path and Domain: Limit cookie scope
- Expires/Max-Age: Limit cookie lifetime
Limitations of Cookie Prefixes
Cookie prefixes don't:
- Prevent server-side vulnerabilities (like SQL injection)
- Prevent network eavesdropping on HTTP connections (you still need HTTPS)
- Prevent attacks that occur before cookies are set
- Control what the server does with the cookie data
They're specifically designed to prevent insecure cookie attributes from being accidentally or maliciously removed.
Fallback for Older Browsers
Since older browsers don't understand cookie prefixes, you should:
- Understand that prefixes provide optional extra security
- Never rely solely on prefixes for security
- Still implement proper security measures (HTTPS, HttpOnly, Secure)
- The prefix just provides an additional guarantee
// Even without prefix support, secure the cookie properly
res.cookie('__Host-session-id', token, {
httpOnly: true, // Always include
secure: true, // Always include
sameSite: 'strict', // Always include
path: '/' // Always include
});
Monitoring and Debugging
Check if cookies are being set correctly:
In browser DevTools:
- Network tab: Look at Set-Cookie headers
- Application tab: View stored cookies
- Console: Check if HttpOnly cookies are visible (they shouldn't be)
On server:
app.use((req, res) => {
console.log('Cookies received:', req.cookies);
console.log('Cookie headers:', req.headers['cookie']);
});
Cookie prefixes are a powerful tool for ensuring cookie security. By using "__Host-" for session cookies and "__Secure-" for other sensitive cookies, you leverage browser-enforced security guarantees that make it difficult or impossible to accidentally create insecure cookies. Combined with other security practices like HTTPS, HttpOnly, and SameSite, cookie prefixes provide defense-in-depth protection for your authentication and session management.