Imagine an exploit where a click on a link quietly changed the victim’s account settings, reset their password or sent a hidden request that they never authorised.
These are some of the egregious impacts that Cross-Site Request Forgery (CSRF) vulnerabilities can achieve – especially if Bug Bounty hunters can chain them with other security flaws.
CSRF exploits the trust between your browser and the site you’re logged into, enabling an attacker to trigger actions on your behalf without a single visible alert. This guide explains the main CSRF vulnerability types and shows how to exploit them with real-world techniques in a structured, step-by-step way.
Outline
- So what is cross-site request forgery (CSRF)?
- How CSRF attacks work – step-by-step
- Impact of CSRF vulnerabilities
- CSRF attack techniques
- POST-based CSRF attacks
- POST-based CSRF scenario
- POST-based CSRF workflow
- GET-Based CSRF attacks
- GET-based CSRF scenario
- GET-based CSRF workflow
- Stored CSRF in user-generated content
- Stored CSRF scenario
- Stored CSRF exploitation workflow
- CSRF in login forms and XSS chain
- Login CSRF and XSS scenario
- Login CSRF and XSS chain workflow
- POST-based CSRF attacks
- Advanced CSRF bypass methods
- Bypassing referer-based CSRF defenses
- CSRF bypass via method override middleware
- CSRF prevention and mitigation best practices
- Synchronizer Token Pattern (STP)
- Double Submit Cookies
- SameSite attribute
- Prompting user interaction
- Conclusion
- References and further reading
So what is cross-site request forgery (CSRF)?
In simple terms, CSRF occurs when a website allows an attacker to trick a user’s web browser into performing unwanted actions on a trusted site where the victim is authenticated.
Consider this example: you’re logged into your bank account and browsing another website in a different tab. Now, imagine that second website contains some hidden code that sends a request to your bank to transfer money to the attacker’s account.
Because you're already logged into your bank, your browser automatically includes your session cookie with the request, making it appear legitimate. The bank website, which lacks best-practice CSRF protections, duly processes the transfer.
That's the essence of a CSRF attack: an attacker is essentially forging a request on your behalf by exploiting the trust a website has in a user’s authenticated session.
This trust is embodied by the cookie set by the website in your browser to remember your session once you log in. This session cookie is automatically included with every subsequent request you make to that website. This is why you can close the browser, return later and you’ll still be logged in.
If a site lacks robust CSRF protections, an attacker can abuse trust in these cookies to force a user to perform actions like changing their email address or password, or even making purchases without their knowledge or consent.
How CSRF attacks work – step-by-step
A successful CSRF attack entails the following steps:
- The attacker identifies and recons a web application that is vulnerable to CSRF
- The attacker crafts a malicious request tailored to the vulnerable functionality
- The malicious request is delivered to the victim via a webpage, email or injected content
- The victim is tricked into executing the request, usually by visiting a malicious site
- The victim’s browser automatically includes their valid session cookie with the forged request
- The vulnerable website processes the request as if it were legitimate – triggering an unwanted action on the victim’s account
Impact of CSRF vulnerabilities
The impact of a CSRF attack can vary significantly. Since it enables attacks to perform state-changing actions as authenticated users, it can lead to serious consequences – including data theft, unauthorised funds transfers or even full account takeover – without the victim noticing. If the attacker compromises a high-privilege administrator or dev account, the outcome can escalate to full system compromise.
RELATED SQL injection for Bug Bounty hunters
POST-based CSRF attacks
A POST-based CSRF vulnerability occurs when an attacker tricks a logged-in user’s browser into sending a cross-site POST request that triggers a state-changing action without proper anti-CSRF protections, or by bypassing those protections.
To exploit this:
- The attacker sets up a server hosting an HTML form that automatically submits a POST request to the vulnerable web application
- Client-side JavaScript is typically used to trigger this submission without user interaction
- The attacker then sends the victim a link to a malicious server. When clicked, the crafted POST request is sent with the victim’s session cookie, executing the unwanted action
POST-based CSRF is often a little harder to exploit than GET-based CSRF (which we’ll cover in the next section) since the attacker usually needs a hidden form for auto-submission. However, the impact is usually greater, since state changes are commonly implemented by POST.
POST-based CSRF scenario
Imagine a vulnerable content management system (CMS). You discover a POST-based CSRF in the feature for changing user roles. It transpires that this feature accepts an empty CSRF token and still performs the action.
HTTP request:
POST /admin/users/role HTTP/2
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
username=guest&role=admin&csrf=
Now you set up a malicious server hosting an HTML POST form that triggers a role change for your guest user account:
<html>
<!-- CSRF PoC - generated by Burp Suite Professional -->
<body>
<form action="https://example.com/admin/users/role" method="POST">
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="role" value="admin" />
<input type="hidden" name="csrf" value="" />
<input type="submit" value="Submit request" />
</form>
<script> history.pushState('', '', '/'); document.forms[0].submit(); </script>
</body>
</html>
Email the administrator a link to the server containing this code and, if the administrator clicks the link, your user account gains administrator privileges on the CMS.
POST-based CSRF workflow
GET-Based CSRF attacks
GET-based CSRF attacks are typically easier to exploit than POST-based attacks, because an attacker only needs to trick the victim into making a request – often just by visiting a URL – rather than submitting a form.
Let’s say an attacker sets an HTML image tag’s src
attribute to point to a vulnerable endpoint. When the victim's browser tries to load the image, it inadvertently triggers the CSRF vulnerability by issuing a GET request to the image’s URL.
GET-based CSRF scenario
Suppose an application allows users to change their email address in account settings via a GET request such as: http://example.com/account/settings?newEmail=attacker@example.com
Crucially, there's no CSRF token in place.
Since no CSRF token is enforced, this payload will force the victim to perform a GET request to the vulnerable endpoint:
<img src="http://example.com/account/settings?newEmail=attacker@example.com">
In this scenario, an attacker could trick the victim into loading the malicious URL – whether by embedding it in an image tag, sending a crafted link or including it in an email. If the victim is logged in when their browser makes the request, the application will process it as if the victim themselves submitted the change.
As a result, the victim’s account email would be silently updated to the attacker’s address, without any explicit action or awareness on the victim’s part.
GET-based CSRF workflow
Stored CSRF in user-generated content
When a web application allows user-generated HTML content (such as through a rich-text editor) or contains HTML injection vulnerabilities, stored CSRF attacks can be possible against endpoints vulnerable to GET-based requests.
For example, if blog comments support embedded images, an attacker could craft an <img>
tag whose src
attribute points to a CSRF-vulnerable endpoint. When the victim views content containing this tag, their browser automatically attempts to load the image – triggering a malicious GET request that executes the CSRF.
If the attacker can create blog posts, leave comments or send private messages within the vulnerable application, they can persistently store this malicious image. Any user who views the infected content will unknowingly trigger the CSRF.
Stored CSRF scenario
Let’s say you’re pentesting a web application and discover that users can add images to blog-post comments. Then you discover you can delete your account with a GET request – even though the request appear to use a CSRF token. The issue? The token isn’t tied to the user session – which means the same CSRF token works for all users!
Stored CSRF exploitation workflow
CSRF in login forms and XSS chain
CSRF issues in login forms must usually be chained with other vulnerabilities to be truly impactful. A common scenario is chaining login CSRF with authenticated XSS.
Login CSRF and XSS scenario
Imagine you discover a stored XSS vulnerability within an authenticated area of your account, such as the settings page. To weaponize it, you can chain it with a CSRF vulnerability in the login form.
The CSRF payload forces the victim to log into the compromised account. Once they are authenticated, the stored XSS executes malicious code in the victim’s browser.
Login CSRF and XSS chain workflow
Advanced CSRF bypass methods
CSRF defences come in many forms, as do the techniques used to circumvent them. Common defence measures include validating the Referer
or Origin
headers, implementing anti-CSRF tokens, or restricting sensitive actions to ‘non-form’ HTTP methods like PUT or DELETE, under the assumption that HTML forms cannot issue such requests.
However, these protections can often be bypassed through various advanced techniques.
Bypassing referer-based CSRF defenses
If the Referer
header is not from the same origin or trusted domain, the request fails validation and is denied. However, many implementations only check the Referer
header when it is present. So to bypass this defence, an attacker can use an HTML <meta>
tag to suppress the Referer
header:
<meta name="referrer" content="never">
CSRF bypass via method override middleware
Many web application frameworks (such as Laravel, Symfony, and Express) support an HTTP override parameter, commonly _method
.
This parameter, which is frequently used in RESTful applications, enables attackers to manipulate the HTTP method used by the request.
Standard HTML forms are typically limited to GET and POST requests, but _method
allows developers to emulate PUT, PATCH or DELETE.
A developer might fail to implement CSRF protections on an endpoint that uses DELETE based on the mistaken assumption that CSRF attacks are not viable.
Suppose an endpoint accepts the following request to delete a user:
POST /users/delete HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=admin&_method=DELETE
An attacker can trick a victim into submitting this request via a hidden HTML form:
<!-- Delete a user using the HTTP method: DELETE -->
<form method="POST" action="/users/delete">
<input name="username" value="">
<input type="hidden" name="_method" value="DELETE">
<button type="submit">Delete User</button>
</form>
CSRF prevention and mitigation best practices
How can we defend against CSRF attacks? There are several proven techniques.
The Synchronizer Token Pattern (STP) technique involves the server generating a unique, unpredictable token for each user session. This token is embedded within every HTML form.
When a form is submitted, the server checks whether the token in the request matches the stored session token. Matching tokens indicate legitimate requests; mismatches signal potential CSRF attempt and the requests are rejected.
With Double Submit Cookies, the server generates a random value, sets it as a cookie in the browser and includes it in a hidden form field.
When a form is submitted, the server verifies that the cookie value and hidden field value match. If they don’t, the request is rejected.
The SameSite attribute controls whether cookies are sent with cross-site requests. Setting SameSite to Strict means cookies are only sent for same-site requests – offering stronger protection but with the risk of breaking external link workflows.
Lax allows cookies with top-level GET requests that navigate the user to the origin site, balancing security and usability. For example, following external links to your bank site might be permitted under Lax but not Strict.
Prompting user interaction for sensitive actions adds another layer of defence against CSRF nasties. This could involve asking users to re-enter their password, answer a security question or tick a checkbox in order to verify that the legitimate user is making the change.
Conclusion
CSRF attacks might seem comparatively straightforward but they can have serious consequences – particularly when targeting high-privilege accounts or chaining them with vulnerabilities like XSS.
CSRF issues have, however, become less prevalent thanks to the emergence of effective protections. A layered approach – combining CSRF tokens, same-site cookie settings, and user confirmations for important actions – can greatly reduce the risk.
Yet plenty of CSRF vulnerabilities still lie ready to be discovered – especially in legacy applications and poorly implemented systems – by Bug Bounty hunters who deploy the techniques outlined in this article.
And if you chain them with other vulnerabilities, then high and critical bounties are readily achievable. Happy hunting!
References and further reading
- Cross-site request forgery (CSRF) learning materials and labs on PortSwigger’s Web Security Academy
- Cross-site request forgery (CSRF) attacks explained by OWASP
- Cross-site request forgery page on Wikipedia
- 'Blind Attacks: Understanding CSRF' by Zell Liew on Hackernoon
RELATED SQL injection for Bug Bounty hunters
HANDS-ON HACKING TRAINING Tackle labs and CTF challenges around common vulnerabilities on Dojo, our CTF training platform for bug hunters