You’re logged in to your bank account.
In another tab, you open a random website. Maybe it contains a malicious ad, or maybe the whole page is malicious.
That second website sends a request to your bank:
POST /transfer
amount=5000&to=attacker
You never opened the transfer page.
You never clicked “Confirm.”
But the request may still include your session cookie automatically.
And if the bank only checks that cookie, it may treat the request as if it came from you.
That’s Cross-Site Request Forgery, or CSRF.
The browser isn’t leaking your cookie
There’s an important distinction here.
The malicious website doesn’t necessarily need to read or steal your session cookie.
It only needs the browser to attach it to a request sent to the vulnerable website.
The attacker usually can’t read the response because of the browser’s same-origin policy. But for actions like changing an email address or transferring money, reading the response may not matter.
The damage is already done.
CSRF can target any state-changing action, such as:
- Changing an email address
- Updating a password
- Transferring money
- Deleting an account
- Changing account settings
The exact impact depends on what the vulnerable endpoint allows.
How do CSRF tokens stop this?
One of the most common defenses is an anti-CSRF token.
The server generates a secret, unpredictable token associated with the user’s session and exposes it to the legitimate frontend.
When the frontend sends a state-changing request, it includes that token:
POST /transfer
X-CSRF-Token: random-secret-value
The server then compares the received token with the expected one.
If the token is missing or invalid, the request is rejected.
The attacker’s website might be able to trigger a request, but it cannot obtain the valid token from your website because of the browser’s same-origin protections.
That missing piece is what makes the forged request fail. CSRF tokens can be sent through hidden form fields, request bodies, or custom headers, depending on the application. OWASP’s CSRF Prevention Cheat Sheet
What about SameSite cookies?
The SameSite cookie attribute tells the browser when a cookie should be included with cross-site requests.
For example:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax
The available values include:
Strict: the cookie is only sent with same-site requests.
Lax: blocks the cookie on most cross-site subrequests, but still allows it during certain top-level navigations.
None: allows cross-site requests and requires Secure.
So SameSite makes many CSRF attacks much harder, but Lax doesn’t mean the cookie will never be included in a cross-site request. It’s better treated as one layer of protection rather than an excuse to ignore the rest of your CSRF defenses. MDN: Set-Cookie and SameSite
CSRF vs. XSS
The easiest mental model is:
With XSS, the attacker gets JavaScript to run inside the trusted website.
With CSRF, the attacker tricks the victim’s browser into sending an authenticated request to the trusted website.
XSS can often bypass CSRF protections because the malicious code is already running inside the application’s origin.
CSRF doesn’t need to steal your session.
It uses the session while it’s still sitting safely inside your browser.
This was post #4 in my Frontend Security series.
If you’d like to catch up on the previous posts:
- Content Security Policy (CSP): Read the post
- Cross-Site Scripting (XSS): Read the post
More frontend security topics are coming soon.
Top comments (0)