Q4 of 24 · Security

What cookie security flags exist and how do you verify they are correctly set?

SecurityJuniorsecuritycookieshttponlysecuresamesitecsrfxsstesting

Short answer

Short answer: HttpOnly prevents JavaScript from reading the cookie (mitigates XSS-based session theft). Secure ensures the cookie is only sent over HTTPS. SameSite=Strict or Lax restricts cross-origin sending (mitigates CSRF). Verify all three via the Set-Cookie response header in browser DevTools, a proxy tool, or an API test assertion.

Detail

HttpOnly: the cookie is not accessible via document.cookie in JavaScript. An XSS attack that injects JavaScript cannot steal an HttpOnly cookie. Session tokens must always be HttpOnly.

Secure: the cookie is only included in HTTPS requests, never in HTTP. Without this flag, a session cookie on an HTTPS site is transmitted in plaintext if the user accidentally visits the HTTP version of a URL — a realistic attack on public networks.

SameSite: controls when the browser sends the cookie with cross-origin requests:

  • Strict: cookie is never sent with cross-site requests (breaks some SSO flows and external link navigation where you want the user to arrive authenticated)
  • Lax (the modern default in most browsers): cookie is sent with top-level GET navigations (clicking a link) but not with cross-site POST requests — mitigates CSRF for the most common attack vector
  • None (+ Secure required): cookie is sent with all cross-site requests — required for third-party cookie scenarios (embedded widgets, cross-origin APIs)

How to verify: intercept the Set-Cookie header in the login response. In Playwright:

const [response] = await Promise.all([
  page.waitForResponse(r => r.url().includes('/api/login')),
  loginPage.submitCredentials(),
]);
const setCookie = response.headers()['set-cookie'];
expect(setCookie).toContain('HttpOnly');
expect(setCookie).toContain('Secure');
expect(setCookie).toMatch(/SameSite=(Strict|Lax)/i);

// EXAMPLE

cookie-flags.test.ts

test('session cookie has required security flags', async ({ page, request }) => {
  const response = await request.post('/api/login', {
    data: { email: 'user@example.com', password: 'correct-password' },
  });
  const setCookie = response.headers()['set-cookie'] ?? '';

  expect(setCookie).toContain('HttpOnly');
  expect(setCookie).toContain('Secure');
  expect(setCookie).toMatch(/SameSite=(Strict|Lax)/i);
});

// WHAT INTERVIEWERS LOOK FOR

Can explain what each flag protects against, not just its name. Knows how to check the Set-Cookie header in a test.