The short version
Cross-Site Request Forgery (CSRF) is an attack where a malicious website tricks your browser into making a request to another site where you're already authenticated. Because browsers automatically send cookies with requests, the target site thinks the request is legitimate.
It's tracked as CWE-352 and has been a staple of the OWASP Top 10 for years.
How it works
Let's say you're logged into your bank at bank.com. Your session cookie is stored in the browser.
Now you visit evil.com. That page contains:
<form action="https://bank.com/transfer" method="POST" id="sneaky">
<input type="hidden" name="to" value="attacker" />
<input type="hidden" name="amount" value="10000" />
</form>
<script>document.getElementById('sneaky').submit();</script>
Your browser sends the POST request to bank.com. Because you're logged in, the browser includes your session cookie. The bank's server sees a valid session and processes the transfer.
You never clicked anything. You never saw a form. The attack happened invisibly.
Why cookies make this possible
The core issue is that browsers send cookies automatically with every request to a domain, regardless of where the request originated. It doesn't matter if the request came from bank.com or evil.com. If you have cookies for bank.com, they get included.
This is how cookies are designed to work. CSRF exploits that design.
How to prevent it
SameSite cookies (the modern way)
The SameSite attribute on cookies is the most effective defense. As explained in the MDN Set-Cookie documentation:
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
SameSite=Lax prevents the cookie from being sent with cross-site POST requests, form submissions from other sites, and AJAX calls. It still sends the cookie for top-level navigations (clicking a link), so the user stays logged in when following links.
SameSite=Strict goes further: the cookie is never sent with any cross-site request. More secure but can be annoying if users bookmark or share links.
Modern browsers default to SameSite=Lax if no value is specified.
CSRF tokens (the classic way)
Before SameSite cookies, the standard defense was CSRF tokens. The server generates a random, unpredictable token and includes it in every form:
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="random-unique-token" />
<!-- other fields -->
</form>
When the form is submitted, the server checks that the token matches what it generated. Since the attacker's site can't read tokens from your pages (same-origin policy prevents it), they can't include the correct token in their forged request.
The OWASP CSRF Prevention Cheat Sheet covers multiple implementation patterns.
Check the Origin header
The server can check the Origin or Referer header on incoming requests. If a POST to bank.com/transfer comes from evil.com, reject it. This isn't foolproof (some browsers strip the Referer), but it's a useful additional layer.
Common mistakes
Relying only on "the user must be logged in." CSRF doesn't bypass authentication. It exploits it. The user IS logged in, that's the whole point.
Using GET requests for state-changing actions. If /delete-account?confirm=true works with a GET request, CSRF becomes trivial. An <img> tag is enough:
<img src="https://yourapp.com/delete-account?confirm=true" />
State-changing actions should always use POST, PUT, or DELETE.
Assuming AJAX calls are safe. Cross-origin AJAX is restricted by CORS, but simple form submissions are not. CSRF typically uses form submissions, not AJAX.
The modern landscape
With SameSite=Lax as the browser default, CSRF is less of a threat than it used to be. But not all cookies are set with SameSite, not all browsers enforce the default, and legacy applications often have cookies without any SameSite attribute.
Don't assume you're safe. Check your cookies.
Check your site
Want to know if your site has this issue? Scan it now and find out in 60 seconds.
Frequently Asked Questions
- What is CSRF in simple terms?
- CSRF is when a malicious website makes your browser send a request to a site where you're already logged in. Because the browser automatically includes your cookies, the request looks legitimate to the server.
- Does SameSite cookie attribute prevent CSRF?
- SameSite=Lax prevents most CSRF attacks by not sending cookies with cross-site POST requests. SameSite=Strict provides even stronger protection but can affect usability.
- Do I need CSRF tokens if I use SameSite cookies?
- SameSite=Lax covers most cases, but CSRF tokens provide defense-in-depth. If your application performs sensitive actions, using both is the safest approach.
Your AI writes the code. We find what it missed.
Paste your URL. Security audit in 60 seconds.
Scan my app