Skip to content
SEO Optimizer is live, Audit on page SEO and AI-search readiness. Try it free
Iniciar sesión

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.

For how the attack works in the first place, see what is a CSRF attack. This guide covers the fix.

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:

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

The victim's browser sends the request to yourbank.com with 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

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

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

server.tsValidate before processing any state-changing request
app.post("/transfer", (req, res) => {
  if (!validateCsrfToken(req.session, req.body.csrf_token)) {
    return res.status(403).send("Invalid CSRF token");
  }
  // process the transfer
});

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 - see our API security basics guide for the broader pattern - 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=Lax on 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.

Preguntas frecuentes

Preguntas frecuentes

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.

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.

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.

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.

Gratis - sin necesidad de registro

Check this on your own site

Run a free scan and see exactly where you stand - no sign-up required.

Ejecutar auditoría gratis