A CSRF attack (cross-site request forgery) tricks a victim's browser into sending an authenticated request to a site where the victim is already logged in, so the server performs an action the user never intended, using the user's own session credentials. The attacker never sees the response and never steals the session. They abuse the fact that browsers attach cookies automatically to every request to a domain, whether the request came from the real app or from an attacker's page.
That automatic-cookie behavior is the entire vulnerability, and it is also the reason the standard defense (a secret token the attacker cannot guess) works.
How does a CSRF attack work?
The setup requires three conditions: the victim is authenticated to a target site, the site performs a state-changing action from a predictable request, and the site relies only on the cookie to authorize it.
Here is the sequence. A user logs into their bank, which sets a session cookie. Without logging out, they visit a malicious page. That page contains a hidden form or an image tag pointing at the bank's transfer endpoint with attacker-chosen parameters. The browser, seeing a request to the bank's domain, automatically attaches the bank session cookie. The bank sees a valid session and a well-formed request and processes the transfer.
For a GET-based action, even an image tag is enough:
<img src="https://bank.example/transfer?to=attacker&amount=1000">
For a POST action, the attacker uses an auto-submitting form on their page. The victim only has to load the malicious page while logged in elsewhere. There is no need for XSS, no script running on the target site, and no stolen password.
What is the difference between CSRF and XSS?
They are often confused because both are client-side web attacks, but they exploit different trust.
- XSS runs attacker-controlled JavaScript inside the victim's session on the vulnerable site. It can read responses, steal tokens, and do anything the user can.
- CSRF runs no script on the target. It forges a blind request from another origin, relying on the browser to attach credentials. The attacker cannot read the response.
An important consequence: XSS defeats CSRF defenses. If an attacker can run script on your page, they can read the anti-CSRF token and include it, so fixing XSS is a prerequisite for CSRF protection to mean anything.
What is a CSRF token and how does it stop the attack?
If you have wondered "what is a CSRF token," it is a secret, unpredictable value the server generates per session (or per request) and embeds in legitimate forms. When the form is submitted, the server checks that the request carries the matching token. Because an attacker's cross-origin page cannot read the token out of your site (the same-origin policy blocks it), it cannot forge a request that passes the check.
The pattern is the synchronizer token pattern:
- On rendering a form, the server includes a hidden field with the token.
- The token is tied to the user's session server-side.
- On submission, the server compares the submitted token to the stored one and rejects mismatches.
A stateless variant, the double-submit cookie, sets the token in both a cookie and a request parameter and verifies they match, avoiding server-side storage. Either way, the defense hinges on a value the attacker cannot obtain from another origin.
What are the modern defenses beyond CSRF tokens?
Tokens remain the primary control, but browsers have added strong layers.
- SameSite cookies. Setting
SameSite=Lax(now the default in major browsers) orSameSite=Stricttells the browser not to send the cookie on cross-site requests, which neutralizes the classic CSRF vector for most flows.Laxstill allows top-level GET navigations, so it is not a full replacement for tokens on GET-triggered actions. - Origin and Referer checks. Verifying the
OriginorRefererheader matches your site rejects cross-origin form posts. - Custom request headers for APIs. JSON APIs that require a custom header (for example, a header set by your front-end code) are protected because cross-origin pages cannot set custom headers on simple requests without a CORS preflight the server controls.
- Avoid state changes on GET. Idempotent, side-effect-free GET handlers remove the easiest CSRF target.
Use tokens and SameSite together. SameSite is excellent defense in depth, but relying on it alone leaves gaps around GET actions and older clients.
How do you find CSRF gaps before shipping?
CSRF is a design flaw as much as a coding bug, so review both the framework configuration and the endpoints.
- Confirm your framework's CSRF protection is enabled and not disabled per route "temporarily."
- Check that every state-changing endpoint requires a token or a custom header, including newer API routes that bypassed the form flow.
- Verify cookies set
SameSiteandSecure. - Fix XSS first, since it invalidates CSRF defenses.
Dynamic testing that drives the running application can confirm whether an endpoint accepts forged cross-origin requests, and static analysis flags routes that mutate state without protection. Safeguard's SAST and DAST cover both angles, and for a broader model of injection and request-forgery classes the Safeguard Academy has a web-attacks track.
FAQ
What is a CSRF token in simple terms?
A secret, unguessable value the server puts in your legitimate forms and then checks on submission. Because a cross-origin attacker's page cannot read that value out of your site, it cannot forge a request that includes the correct token, so the forged request is rejected.
Do SameSite cookies make CSRF tokens unnecessary?
Not entirely. SameSite=Lax (the modern default) blocks most cross-site cookie sending, but it still permits cookies on top-level GET navigations, and older clients may not enforce it. Use SameSite as strong defense in depth alongside tokens, not as a full replacement.
Can a CSRF attack steal my password or session?
No. A CSRF attack cannot read the response and does not steal credentials. It forges an action using the session the browser already has. That is why the damage is unauthorized actions (transfers, setting changes) rather than data theft, which is more the domain of XSS.
Does CSRF affect APIs and single-page apps?
It can. If an API authenticates with cookies, it is exposed to CSRF just like a form. APIs that use bearer tokens in an Authorization header set by JavaScript are generally safe, because the browser does not attach that header automatically to cross-origin requests.