← All fixes

Fix it

Session cookie without httpOnly, secure, and sameSite, how to fix it

Medium severityCWE-1004 (Sensitive Cookie Without HttpOnly Flag)
We scanned nearly 2,000 AI-built apps and 1 in 8 shipped a high-severity flaw. Is this one in yours?Scan free →

When you set a session cookie, the flags matter as much as the value. Without httpOnly, page scripts can read it. Without secure, it can travel over plain HTTP where it is easy to intercept. Without sameSite, the browser attaches it to cross-site requests, which enables CSRF. The fix is to set all three, and it is a one-line change.

Why it's a problem

Each missing flag removes a specific protection. No httpOnly means an XSS bug can steal the session. No secure means the cookie can leak on any non-HTTPS request or downgrade. No sameSite means another site can make the browser send the cookie on a forged request. Because the cookie authenticates the user, weakening its flags weakens every route that trusts the session.

The pattern

// flags omitted: readable by JS, sent over HTTP, attached cross-site
res.cookie("session", sessionId);

The fix

res.cookie("session", sessionId, {
  httpOnly: true,   // scripts cannot read it
  secure: true,     // HTTPS only
  sameSite: "lax",  // not sent on cross-site requests by default
  maxAge: 60 * 60 * 1000,
  path: "/",
});

Why AI tools write this

The minimal cookie call works in development, where the app runs over http://localhost and nothing cross-site is happening, so the missing flags never cause a visible problem. The assistant optimizes for code that runs now, and the insecure defaults only bite in production. It also frequently omits secure specifically because it breaks local HTTP testing.

The quick fix

  • Set httpOnly: true, secure: true, and sameSite: 'lax' (or 'strict') on every session cookie.
  • Gate secure on an environment flag if you need local HTTP, but keep it on in production.
  • Set a sensible maxAge or expiry so sessions do not live forever.
  • Use 'strict' sameSite for cookies that should never be sent cross-site.

Common questions

What does sameSite: 'lax' vs 'strict' actually do?

lax blocks the cookie on cross-site POST, PUT, and DELETE but allows it on top-level navigations like clicking a link. strict blocks it on all cross-site requests, including navigating from another site, which can log users out when following links.

If I set httpOnly on the session cookie, can my JavaScript still call authenticated endpoints?

Yes. The cookie is sent automatically by the browser with every request to your domain using credentials: 'include'. Your JavaScript does not need to read the token; the browser handles it.

What is a sensible maxAge for a session cookie?

Common practice is 24 hours to 30 days depending on the security requirements. For high-security flows, use a shorter window. Setting no maxAge creates a session cookie that expires when the browser closes.

Want to know if this pattern is already in something you shipped? Scan your live app or a public repo free, no account needed.

Scan my app →

Related: JWT in localStorage

Catch this automatically: scan your GitHub repo · website vulnerability scanner · review every pull request · SAST for AI code · OWASP Top 10 for AI code

Session Cookie Missing httpOnly and Secure Flags — How to Fix It | Prbl