Session Cookie Flags: Secure, HttpOnly, SameSite

Without these three flags, an admin session can be hijacked via XSS, HTTP sniffing, or CSRF. Configure them correctly.

WordPress session cookies (including wordpress_logged_in_*, wordpress_sec_* and any generic PHP session cookie) are effectively the keys to an account. Anyone who steals the cookie value becomes the user — no password, no 2FA needed. The three flags Secure, HttpOnly, and SameSite raise the bar on stealing those cookies. If even one is missing, an attack path stays open.

Why this matters

Without Secure, the browser will send the cookie over plain HTTP — a visitor on a coffee-shop Wi-Fi who first hits http://example.com exposes the cookie value to anyone listening on the network. Tools like sslstrip exist precisely to coerce that downgrade. Without HttpOnly, JavaScript can read the cookie via document.cookie. If any plugin or theme has an XSS bug — even a small reflected XSS on a 404 page — an attacker-injected script can collect the admin cookie and send it to a remote endpoint. Without SameSite, a malicious site that the admin happens to visit can submit a POST to wp-admin/admin-post.php on your domain; the browser attaches the session cookie automatically, and CSRF succeeds despite nonces in some flows.

How to detect

Open Chrome DevTools > Application > Cookies > select your domain. For every cookie (especially wordpress_logged_in_* and PHPSESSID), confirm Secure and HttpOnly are checked, and SameSite is Lax or Strict. From the shell:

curl -I -c /tmp/cookies https://example.com/wp-login.php
grep -E "Set-Cookie|HttpOnly|Secure|SameSite" /tmp/cookies

How to fix

Add to wp-config.php before require_once ABSPATH . 'wp-settings.php';:

// Force Secure on WP auth cookies
define('COOKIE_SECURE', true);
define('FORCE_SSL_ADMIN', true);

// PHP session cookies (if PHP sessions are used)
@ini_set('session.cookie_secure', 1);
@ini_set('session.cookie_httponly', 1);
@ini_set('session.cookie_samesite', 'Lax');
@ini_set('session.use_only_cookies', 1);

WordPress has flagged auth cookies as HttpOnly since version 2.5, but it does not always mark Secure automatically — that is why COOKIE_SECURE is essential. To enforce at the web server layer (useful when PHP-FPM ignores ini_set):

# In root .htaccess
<IfModule mod_headers.c>
    Header edit Set-Cookie ^(.*)$ "$1; HttpOnly; Secure; SameSite=Lax"
</IfModule>
# In Nginx
proxy_cookie_path / "/; HTTPOnly; Secure; SameSite=Lax";

Common mistakes

Mistake one: setting SameSite=Strict on a site that has a checkout flow redirecting to PayPal or Stripe and back. Strict will not send the cookie on the return hop, logging the user out. Lax is almost always the right choice. Mistake two: configuring only php.ini but forgetting COOKIE_SECURE — the WP auth cookies are not affected by PHP session settings. Mistake three: enabling FORCE_SSL_ADMIN while internal routes still serve HTTP — this can produce redirect loops.

Verifying the fix

Log out and log back in so WordPress issues fresh cookies. In DevTools > Application > Cookies, confirm each cookie has Secure=true, HttpOnly=true, SameSite=Lax. Re-run the audit. As an extra check, use cookieserve.com or cookiestatus.com to confirm the browser receives the expected flags.

Tip: If something breaks after enabling SameSite=Lax (for example, opening WP inside an iframe on another domain), consider SameSite=None; Secure — it permits cross-site contexts but requires HTTPS.