Cross-Site Request Forgery (CSRF)

Description

Cross-Site Request Forgery (CSRF) is a vulnerability that occurs when a web application does not sufficiently verify whether a request came from an authorized user or was forged by an attacker. CSRF attacks trick authenticated users into executing unintended actions by exploiting the trust a web application has in the user's browser. When a victim visits a malicious page or clicks a crafted link while authenticated to a target site, their browser automatically includes session cookies, causing the server to process the attacker's request as if it were legitimate.

Risk

CSRF attacks can have severe consequences depending on the targeted functionality. Attackers can force users to change account settings, make purchases, transfer funds, modify data, or perform any action the victim is authorized to perform. The Samy worm on MySpace demonstrated the viral potential of CSRF combined with XSS, spreading across millions of profiles in hours. Administrative CSRF attacks can compromise entire applications by forcing admins to create attacker-controlled accounts or change security settings. The vulnerability is particularly dangerous because the victim's browser provides all necessary authentication automatically.

Solution

Implement anti-CSRF tokens (synchronizer tokens) in forms and AJAX requests. Tokens should be unique per session and validated server-side before processing requests. Use the SameSite cookie attribute to prevent cookies from being sent with cross-site requests. Verify the Origin and Referer headers for state-changing operations. Require re-authentication for critical actions. Consider implementing custom request headers for AJAX requests. Apply defense in depth with multiple countermeasures.

Common Consequences

ImpactDetails
IntegrityScope: Unauthorized Actions

Attackers execute actions as the authenticated user, including data modification, purchases, and account changes.
Access ControlScope: Account Compromise

Password changes, email updates, or security question modifications enable account takeover.
ConfidentialityScope: Data Exfiltration

CSRF combined with other vulnerabilities can expose or transfer user data.

Example Code + Solution Code

Vulnerable Code

<!-- VULNERABLE: Form without CSRF protection -->
<form action="/transfer" method="POST">
    <input name="to_account" value="">
    <input name="amount" value="">
    <button type="submit">Transfer</button>
</form>

<!-- Attacker's page -->
<html>
<body>
    <!-- Auto-submitting hidden form -->
    <form id="csrf" action="https://bank.com/transfer" method="POST">
        <input type="hidden" name="to_account" value="attacker">
        <input type="hidden" name="amount" value="10000">
    </form>
    <script>document.getElementById('csrf').submit();</script>
</body>
</html>
# VULNERABLE: No CSRF validation
@app.route('/change-password', methods=['POST'])
def change_password():
    # No CSRF token check - attacker can forge this request
    new_password = request.form['new_password']
    user = get_current_user()
    user.set_password(new_password)
    return 'Password changed'

@app.route('/delete-account', methods=['POST'])
def delete_account():
    # No CSRF protection on critical action!
    user = get_current_user()
    user.delete()
    return 'Account deleted'

Fixed Code

<!-- SAFE: Form with CSRF token -->
<form action="/transfer" method="POST">
    <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
    <input name="to_account" value="">
    <input name="amount" value="">
    <button type="submit">Transfer</button>
</form>
from flask import Flask, session, request, abort
from flask_wtf.csrf import CSRFProtect
import secrets

app = Flask(__name__)
app.secret_key = secrets.token_hex(32)
csrf = CSRFProtect(app)  # Enable CSRF protection globally

# SAFE: CSRF token validated automatically by Flask-WTF
@app.route('/change-password', methods=['POST'])
@csrf.protect  # Validates CSRF token
def change_password():
    new_password = request.form['new_password']
    user = get_current_user()
    user.set_password(new_password)
    return 'Password changed'

# Manual CSRF validation example
def validate_csrf_token(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.form.get('csrf_token')
        if not token or token != session.get('csrf_token'):
            abort(403, 'CSRF validation failed')
        return f(*args, **kwargs)
    return decorated

@app.before_request
def generate_csrf_token():
    if 'csrf_token' not in session:
        session['csrf_token'] = secrets.token_hex(32)

# SAFE: Additional protections
@app.route('/delete-account', methods=['POST'])
@csrf.protect
def delete_account():
    # Require re-authentication for critical actions
    password = request.form.get('confirm_password')
    user = get_current_user()

    if not user.verify_password(password):
        abort(403, 'Password confirmation required')

    user.delete()
    return 'Account deleted'
// SAFE: AJAX with CSRF token
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

fetch('/api/update-profile', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken  // Custom header for AJAX
    },
    body: JSON.stringify(data),
    credentials: 'same-origin'  // Include cookies
});
# Set SameSite cookie attribute
@app.after_request
def set_cookie_flags(response):
    # SameSite=Strict prevents cookies on cross-site requests
    # SameSite=Lax allows GET navigation but blocks POST
    response.set_cookie('session', value=session_id,
                        samesite='Strict', secure=True, httponly=True)
    return response

Exploited in the Wild

Samy Worm (MySpace, 2005)

The Samy worm combined XSS and CSRF to spread across MySpace, adding the attacker as a friend and inserting malicious code into victim profiles. It infected over one million users within 24 hours, demonstrating the devastating potential of CSRF vulnerabilities.

uTorrent Remote Code Execution (uTorrent, 2008)

A CSRF vulnerability in uTorrent's web interface allowed attackers to force downloads of malicious torrents when victims visited attacker-controlled websites while uTorrent was running.

ERPNext Account Takeover (ERPNext, 2025)

CVE-2025 in ERPNext 14.82.1 enables account takeover through CSRF, affecting enterprise resource planning systems.


Tools to test/exploit

  • Burp Suite — CSRF PoC generator and testing capabilities.

  • OWASP ZAP — automated CSRF vulnerability detection.

  • CSRFTester — OWASP tool for CSRF testing.


CVE Examples


References

  1. MITRE. "CWE-352: Cross-Site Request Forgery (CSRF)." https://cwe.mitre.org/data/definitions/352.html

  2. OWASP. "Cross-Site Request Forgery Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html