CSRF: requests your users never meant to send

Cross-site request forgery abuses the fact that browsers attach cookies automatically. Another site can make a logged-in visitor's browser submit a form to yours, and the session cookie goes along.

Example

Vulnerable
app.use(session({ secret: process.env.SESSION_SECRET }));

app.post("/transfer", isLoggedIn, (req, res) => {
  transfer(req.session.userId, req.body.to, req.body.amount);
  res.redirect("/account");
});
Fixed
app.use(session({
  secret: process.env.SESSION_SECRET,
  cookie: { secure: true, httpOnly: true, sameSite: "lax" },
}));
app.use(doubleCsrfProtection); // csrf-csrf, or lusca.csrf()

app.post("/transfer", isLoggedIn, (req, res) => { /* … */ });

How it happens

A page on an attacker's site contains a form that posts to https://your-site.com/transfer and submits itself on load. If your session cookie is sent on cross-site requests and the endpoint accepts any request carrying a valid session, the transfer happens. Cookie sessions without CSRF tokens and without SameSite are the classic setup.

How to fix it

Make a cross-site request unable to look like a real one.

  • Set SameSite=Lax (or Strict) on session cookies
  • Add CSRF tokens to state-changing routes (csrf-csrf, lusca, framework built-ins)
  • Never change state on GET requests
  • For APIs with token auth in a header, CSRF does not apply — cookies are the issue

How RepoVerse finds it

  • ModerateCookie sessions without CSRF protection

    Another site can submit forms to state-changing routes on behalf of a logged-in user — the browser attaches the session cookie automatically.

    data flow · CWE-352

  • LowSession cookie without SameSite

    Browsers that do not default to `Lax` will attach the cookie to cross-site form posts, which is what a CSRF attack relies on.

    website · CWE-1275

Questions

Is SameSite=Lax enough to stop CSRF?
It blocks cross-site POSTs in browsers that support it, which covers most attacks. Tokens are still recommended for older browsers and for flows SameSite does not cover, such as top-level GETs that change state.
How does RepoVerse detect missing CSRF protection?
It looks for cookie-based sessions with state-changing routes, no CSRF middleware and no SameSite setting, and lists the affected routes in the finding.

Related

Updated 2026-10-11