Scanverra

How to Fix Missing CSRF Protection

If a logged-in user visits a malicious page while their session cookie is still active, that page can silently submit a form to your site on their behalf - and the browser happily attaches their real session cookie to it. A CSRF token is what tells your server the request didn't actually come from your own form.

How the Attack Actually Works

The attacker doesn't need to steal a session cookie or bypass authentication - they just need the victim's browser to still be logged in, and to visit a page they control:

A page hosted anywhere, visited by a logged-in victimhtml
1<form action="https://yourbank.com/transfer" method="POST" id="f">
2  <input type="hidden" name="to" value="attacker-account" />
3  <input type="hidden" name="amount" value="5000" />
4</form>
5<script>document.getElementById("f").submit();</script>

The victim's browser sends the request to yourbank.comwith their real session cookie attached - because that's just how cookies work, regardless of which page initiated the request. Without a CSRF token, the server has no way to tell this apart from a legitimate submission.

How to Fix It

1. Generate a per-session (or per-form) token

Token generated server-side, embedded in the formtypescript
1app.get("/transfer", (req, res) => {
2  const csrfToken = generateCsrfToken(req.session);
3  res.render("transfer-form", { csrfToken });
4});
Embed it as a hidden fieldhtml
1<form action="/transfer" method="POST">
2  <input type="hidden" name="csrf_token" value="{{csrfToken}}" />
3  <!-- other fields -->
4</form>

2. Reject the request if the token is missing or wrong

Validate before processing any state-changing requesttypescript
1app.post("/transfer", (req, res) => {
2  if (!validateCsrfToken(req.session, req.body.csrf_token)) {
3    return res.status(403).send("Invalid CSRF token");
4  }
5  // process the transfer
6});

3. Use your framework's built-in CSRF middleware where available

Most mature web frameworks (Django, Rails, Laravel, and Express via csurf or similar) ship CSRF protection you can enable rather than implement by hand - reach for that first before rolling your own token generation and comparison.

4. Pair it with SameSite cookies, don't rely on either alone

SameSite=Laxon the session cookie and a CSRF token on state-changing forms are complementary, not redundant - each closes a gap the other doesn't fully cover.

How Scanverra Detects This

Scanverra's security scan submits test requests to POST forms it finds on your site and flags any that process the request without requiring a CSRF token, so you know exactly which forms are exposed rather than having to audit every one by hand.

FAQ

Frequently asked questions

Doesn't SameSite=Lax on my session cookie already prevent CSRF?

It significantly reduces the risk, but it isn't a complete substitute - SameSite=Lax still allows the cookie on top-level GET navigation, and older browsers or misconfigured subdomains can create gaps. A CSRF token is a defense that doesn't depend on cookie behavior at all, which is why the two are normally used together, not as alternatives.

Do GET requests need CSRF protection?

GET requests shouldn't change state in the first place - if one does (deleting a record via a GET link, for example), that's the actual bug to fix. CSRF tokens are specifically for state-changing requests (POST, PUT, DELETE), which is where the attack applies.

Is a CSRF token the same thing as an API key or auth token?

No - a CSRF token doesn't prove who the user is; the session cookie already does that. It proves the request actually originated from your own page's form, not from a malicious site that tricked the browser into submitting on the user's behalf.

Does an API that uses a Bearer token in an Authorization header need CSRF protection?

Generally no - CSRF exploits the browser automatically attaching cookies to cross-site requests. A token that has to be manually set in a header (not stored in a cookie) isn't attached automatically by the browser, so a cross-site form or script can't replicate it without already having read access to the token.

Free - no sign-up required

Find forms missing CSRF protection

Run a security scan and see which of your forms are exposed to cross-site request forgery.

Run free audit