What is Cross-Site Request Forgery?
Also calledCSRFXSRFSession riding
Definition
Cross-site request forgery is a vulnerability in which a site an attacker controls causes a victim browser to send a state-changing request to a different site where the victim is already authenticated, using credentials the browser attaches automatically.
What cross-site request forgery is
A browser attaches cookies to a request based on where the request is going, not on where it came from. That single behaviour is the whole vulnerability. If an application decides that a valid session cookie is sufficient authorisation for a state-changing action, then any page anywhere on the internet can trigger that action on behalf of anyone who is logged in, because the browser will attach the cookie without being asked.
The attacker never sees the response. This is not an information disclosure class. It is a class about causing an effect: change an email address, transfer a balance, add an API key, promote an account. Anything that reads rather than writes is out of scope for CSRF, which is why the first triage question is always whether the endpoint changes state.
What SameSite changed, and what it did not
Browsers now default cookies to SameSite=Lax when the attribute is absent, which blocks the classic case: a cross-site form POST no longer carries the session cookie. That has made naive CSRF much rarer, and it has also made a generation of testers assume the class is dead. It is not, and the gaps are specific.
- Lax still permits top-level cross-site GET navigation to carry the cookie. An application that changes state on a GET is still exposed.
- A same-site attacker is unaffected. A subdomain the attacker can write to is same-site for cookie purposes, so an XSS or a takeover on any subdomain restores the full class.
- Cookies explicitly set to SameSite=None, which is required for legitimate cross-site embedding, opt back out of the protection entirely.
- Authorization headers and bearer tokens are not cookies. An API that authenticates with a header is not CSRF-exposed in the first place, which is a design answer rather than a mitigation.
What actually fixes it
Bind the request to something the attacker cannot read. A synchroniser token stored server-side against the session and echoed in the request body is the durable answer, because it requires the requesting page to have read a value the same-origin policy prevents a cross-site page from reading. The double-submit variant, where the token is both a cookie and a body field, is cheaper and weaker: it fails against an attacker who can set cookies on the domain, which any subdomain can do.
What it looks like in practice
<!-- A proof of concept for a state-changing POST with no token.
Host it on a domain you control and open it while logged in to the
target in the same browser. It should be run only against a system
you have written permission to test. -->
<html>
<body onload="document.forms[0].submit()">
<form action="https://app.example.com/settings/email" method="POST">
<input type="hidden" name="email" value="[email protected]" />
</form>
<p>If the address changed, the endpoint accepted a cross-site request.</p>
</body>
</html>What it is not
The distinction matters more than the definition does, because these are the terms people swap by accident in a report.
4 cards
Tap a card to reveal the answer. Answers are in the page source, so this works with JavaScript disabled.
What browser behaviour makes CSRF possible?
Cookies are attached based on the destination of a request, not on the origin of the page that caused it, so a cross-site page can trigger an authenticated request.
Why is a read-only endpoint not a CSRF finding?
The attacker never sees the response. CSRF causes an effect rather than disclosing data, so an endpoint that does not change state has nothing to abuse.
Name two situations where SameSite=Lax does not protect you.
State-changing GET requests, which Lax still permits on top-level navigation, and a same-site attacker such as a compromised or attacker-writable subdomain.
Why is the double-submit cookie pattern weaker than a synchroniser token?
It only proves the requester could set a cookie, and any subdomain can set cookies on the parent domain. A synchroniser token proves the requester could read a same-origin response.
Where people get this wrong
Two mistakes, both common. The first is reporting a missing CSRF token on a login form or a search box and being surprised when it is closed: with no state change there is no finding, and the exceptions such as login CSRF need their own impact argument. The second is assuming SameSite=Lax closed the class. It did not, and the subdomain case in particular turns a medium-severity XSS on a forgotten marketing host into a full account takeover on the main application. Always check what else lives on the registrable domain.
Where you can use this
The G1 gate for this template: the artifacts below exist nowhere else in this combination.
- Lab: IDOR in a multi-tenant invoice APIFind an object-level authorisation failure in a tenanted API and demonstrate cross-tenant access without touching another real customer.
- CTF room: Ledger DriftA small internal accounting application with a self-service export feature and an authorisation model that was written before the tenanting was.
Cyber VK Security Curriculum
Pre-publication content owner
Internal ownership label for the web-security curriculum.
Technically reviewed by Cyber VK Lab Engineering
Updated
[ Related ]
- GlossaryServer-Side Request ForgeryServer-side request forgery is a vulnerability in which an attacker causes a server to make an HTTP request to a destination the attacker chooses, using the server as the origin of that request instead of their own machine.
- GlossaryInsecure Direct Object ReferenceAn insecure direct object reference is an access control failure in which an application uses a user-supplied identifier to select a record and does not check that the requesting user is allowed to see that particular record.
- CTF roomLedger DriftA small internal accounting application with a self-service export feature and an authorisation model that was written before the tenanting was.
- LabBlind SSRF to cloud metadataProve that a server-side request forgery with no visible response can still reach an internal service, and write the finding so a triager cannot close it as informational.
- LabIDOR in a multi-tenant invoice APIFind an object-level authorisation failure in a tenanted API and demonstrate cross-tenant access without touching another real customer.
- ArticleWhy your SSRF report gets closed as informationalMost blind SSRF reports are closed without a payout, and usually for the same three reasons. Here is what a triager is actually looking for, and how to supply it without touching anything you should not.