Session cookies are the mechanism most web applications use to maintain authentication state. Once a user logs in, the server issues a session token stored in a cookie — and every subsequent request includes that cookie, proving the user's identity. If an attacker can steal or forge that cookie, they can impersonate the user completely. Correct cookie security flags are the primary defense against this.

The Four Critical Cookie Flags

HttpOnly

The HttpOnly flag prevents JavaScript from accessing the cookie via document.cookie. This is the single most important flag for session cookies. If an attacker manages to inject JavaScript into your page (via XSS), they cannot steal the session token with document.cookie if HttpOnly is set.

Set-Cookie: sessionid=abc123; HttpOnly

The cookie is still sent with every HTTP request — the browser handles this transparently. The only thing prevented is JavaScript read access. There is almost never a legitimate reason for client-side JavaScript to read a session cookie. Set HttpOnly on all session cookies, always.

Secure

The Secure flag instructs the browser to only send the cookie over HTTPS connections, never over plain HTTP. Without it, a user on an HTTP connection (or a network where an attacker can strip HTTPS) would have their session cookie transmitted in plaintext and captured trivially with a network sniffer.

Set-Cookie: sessionid=abc123; HttpOnly; Secure

If your application enforces HTTPS (it should), set Secure on all cookies that contain sensitive data.

SameSite

The SameSite attribute controls when cookies are sent in cross-site requests. This is the primary defense against Cross-Site Request Forgery (CSRF) attacks, where a malicious third-party site tricks a user's browser into making authenticated requests to your application.

Three values are available:

Set-Cookie: sessionid=abc123; HttpOnly; Secure; SameSite=Lax

Domain and Path Scoping

Limit cookies to the narrowest scope they need:

Complete Secure Session Cookie Example

Set-Cookie: sessionid=abc123xyz; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400

Framework-Specific Configuration

Flask (Python):

app.config.update(
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SECURE=True,       # Only over HTTPS
    SESSION_COOKIE_SAMESITE='Lax',
    SESSION_COOKIE_NAME='session',
    PERMANENT_SESSION_LIFETIME=86400  # 24 hours
)

Django:

SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True

Express (Node.js):

app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: {
    httpOnly: true,
    secure: true,
    sameSite: 'lax',
    maxAge: 86400000  // 24 hours in ms
  }
}));

What to Avoid

Checking Your Cookies

Inspect the cookies your application sets:

curl -sI https://yoursite.com/login   -X POST -d "username=test&password=test"   | grep -i "set-cookie"

Every Set-Cookie header for a session cookie should show HttpOnly, Secure, and SameSite. If any flag is missing, it is a finding. Automated scanners check all three on every cookie they observe in responses.