Secure session cookies: the flags and the login step
The session cookie is the account. Three flags decide who can read it and when it is sent, and one line at login decides whether someone else can share it.
Example
app.use(session({
secret: process.env.SESSION_SECRET,
cookie: { httpOnly: false },
}));
function login(req, res, user) {
req.session.userId = user.id; // same session id as before login
}app.set("trust proxy", 1);
app.use(session({
secret: process.env.SESSION_SECRET,
cookie: { secure: true, httpOnly: true, sameSite: "lax", maxAge: 8 * 3600 * 1000 },
}));
function login(req, res, user) {
req.session.regenerate(() => { req.session.userId = user.id; res.redirect("/"); });
}How it goes wrong
Without Secure the cookie also travels over plain HTTP, where anyone on the network can read it. Without HttpOnly, one injected script can read it and send it away. Without SameSite, other sites' forms carry it along. And if the session ID is not changed at login, an ID planted before login stays valid after it — session fixation.
How to fix it
Set the flags explicitly; do not rely on defaults.
- Secure on every cookie of an HTTPS site (behind a proxy, trust it so Express knows)
- HttpOnly on session and auth cookies
- SameSite=Lax or Strict on session cookies
- Regenerate the session on login and destroy it on logout
How RepoVerse finds it
- ModerateSession cookie may be sent over plain HTTP
Without `secure`, the session cookie travels on any HTTP request and can be read on the network. (express-session already sets HttpOnly by default; Secure it does not.)
data flow · CWE-614
- HighSession cookie readable by page scripts
`httpOnly: false` lets any injected script read the session cookie and take over the account.
data flow · CWE-1004
- ModerateSession not regenerated at login
A session id planted before login stays valid after it, so whoever planted it shares the logged-in session.
data flow · CWE-384
- ModerateCookie set without its protective flags
A session cookie without `httpOnly` is readable by script, and without `secure` it travels over plain HTTP.
pattern · CWE-1004
- ModerateCookie set without the Secure flag
The browser will also send this cookie over plain HTTP, where anyone on the network can read it.
website · CWE-614
- ModerateSession cookie readable by page scripts
Without `HttpOnly`, one injected script can read the session cookie and send it away, handing over the logged-in account.
website · CWE-1004
Questions
- Does express-session set HttpOnly by default?
- Yes, express-session's cookie is HttpOnly by default, but not Secure. Setting httpOnly: false or leaving Secure unset are both reported.
- Should anti-CSRF cookies be HttpOnly?
- No. Frameworks such as Django and Angular read the CSRF cookie from JavaScript on purpose, so RepoVerse does not ask for HttpOnly on csrftoken or XSRF-TOKEN cookies.
Related
- CSRF: requests your users never meant to sendHow CSRF (CWE-352) makes a logged-in visitor's browser submit forms to your site, and how CSRF tokens and SameSite cookies stop it in Express and other frameworks.
- Cross-site scripting (XSS): how it works and how to stop itReflected, stored and DOM-based XSS (CWE-79) explained with vulnerable and fixed code, plus the template, CSP and cookie settings that limit the damage.
- HTTPS and HSTS: closing the plain-HTTP gapWhy every site needs HTTPS, a 301 redirect from HTTP and a Strict-Transport-Security header (CWE-319), what max-age to use, and how to avoid mixed content.
Updated 2026-10-11