Stop 3 of 42 · The Front Door · CSRF

A forged slip riding on a real badge

Alice wears her badge all day. Her browser attaches it to every slip she sends to the bank, even slips she never wrote. Mallory leaves a forged slip where Alice will pick it up. The teller sees a valid badge and carries out the order.

Severity Medium–HighCategory Auth WeaknessThe Front DoorSources checked 25 Oct 2026

Watch it happen

Play it as

A forged transfer slip travels to the teller on Alice’s valid badge. The teller trusts the badge and moves the money.

Arrival

Alice is logged in. Her badge cookie has no SameSite protection (None, or a browser with no Lax default), so her browser attaches it to anything sent to the bank, even from other sites.

1 / 5

In bank terms and app terms

In the bankIn your app
Badge pinned on automaticallyThe session cookie your browser sends with every request to your site
Forged slipA hidden form or request on another site that targets your endpoint
Secret stamp on real slipsA CSRF token your server checks on every state-changing request
Teller checking where the slip came fromValidating the Origin header; SameSite cookies make the browser hold the badge back

Are you exposed?

You might be exposed if…
  • You use cookie-based login and your POST, PUT or DELETE routes only check that the user is logged in.
  • Your session cookie uses SameSite=None, or sets no SameSite and relies on a browser default (only some browsers default to Lax).
  • Your forms have no hidden token, and your server never looks at the Origin header.
What to do about it
  1. Set session cookies with SameSite=Lax (or Strict), HttpOnly and Secure.
  2. On every route that changes data, require a CSRF token, or check that Origin matches your own site.
  3. Never change data on a GET request. Keep GETs read-only.

Track these in your to-do list →

It has happened to real companies

Real-world breaches

Netflix (2008) — At the Black Hat DC conference, security researcher Chuck Willis of Mandiant demonstrated a live cross-site request forgery attack on Netflix that added a movie to a logged-in user's queue without their knowledge. He said earlier CSRF problems at Netflix could have changed a user's mailing address, but had been partly fixed. A site that accepts state-changing requests without a CSRF token lets any page the victim visits act as them.

ING Direct (2008) — CSRF allowed attackers to initiate fund transfers from a victim's bank account when they visited a malicious page while logged in.

What it looks like in code

// GOOD: Use SameSite cookies (modern defense)
response.cookies.set("session", token, {
  httpOnly: true,
  secure: true,
  sameSite: "strict"  // or "lax" for GET-safe scenarios
})

// GOOD: Validate Origin header on mutations
const origin = request.headers.get("Origin")
if (origin !== "https://your-app.com") {
  return new Response("Forbidden", { status: 403 })
}

Ask your AI tool to fix it

Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.

Prompt
Protect this app against CSRF. Set all auth cookies with SameSite=Lax (Strict where possible), HttpOnly and Secure. Add middleware that rejects POST, PUT, PATCH and DELETE requests when the Origin header is missing or does not match our own origin, and add CSRF tokens to forms that need them. Make sure no GET route changes data. List each route you protected.

Where this comes from

The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.

Spot a mistake or something out of date? Report a correction · How these guides are made and checked

Go deeper in isitsecure

The free, open-source scanner checks for most of the problems in these guides.