Skip to content

CWE-352: Cross-Site Request Forgery (CSRF)

Overview

Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to perform unwanted actions on a web application. Attackers craft malicious requests that appear to come from legitimate users, exploiting the user's authenticated session. Unlike XSS, which exploits a user's trust in a website, CSRF exploits a website's trust in the user's browser.

OWASP Classification

A01:2025 - Broken Access Control

Risk

CSRF vulnerabilities enable attackers to perform unauthorized actions on behalf of authenticated users:

  • Account takeover: Change email, password, or security settings
  • Financial fraud: Transfer funds, make purchases, change payment methods
  • Data manipulation: Create, modify, or delete user data
  • Privilege escalation: Add administrative users, change permissions
  • System compromise: Execute administrative functions with user credentials

The impact is directly tied to the victim's privileges - CSRF against an administrator can compromise the entire application.

Remediation Steps

Core principle: Never allow authenticated, state-changing requests to be processed unless their origin and authenticity are verified using server-controlled mechanisms.

Identify state-changing endpoints lacking CSRF protection

  • Review the security findings to identify the specific file, line number, and endpoint
  • Identify all state-changing operations (POST, PUT, DELETE, or any action that modifies data)
  • Check which endpoints rely solely on session cookies for authentication
  • Locate forms and AJAX requests that don't include CSRF tokens
  • Review framework configuration to determine if CSRF protection is disabled
  • Map all endpoints that need CSRF protection

Use Synchronizer Token Pattern (Primary Defense)

  • Generate cryptographically random CSRF tokens: Minimum 32 bytes for each user session
  • Store token server-side: Save in user's session
  • Include token in all forms: Add as hidden field <input type="hidden" name="csrf_token" value="...">
  • For AJAX requests, include token in custom headers: X-CSRF-Token: ...
  • Validate token on server: Check for every state-changing request
  • Reject missing/invalid tokens: Return 403 Forbidden for requests without valid token
  • Use framework-provided CSRF protection: Django, Rails, Spring Security, Express csurf
  • Why this works: Attackers cannot read the token due to same-origin policy, so forged requests will fail validation
  • Set SameSite=Strict or SameSite=Lax: On all session cookies
  • Use SameSite=Strict for maximum protection: Cookie sent only for same-site requests
  • Use SameSite=Lax if navigation needed: Allows top-level navigation from external sites
  • Always combine with Secure and HttpOnly flags: HTTPS only, prevent JavaScript access
  • Example: Set-Cookie: sessionid=...; SameSite=Strict; Secure; HttpOnly
  • Note: SameSite provides defense-in-depth but should not be the only protection

Apply Origin and Referer header validation

  • Validate Origin header: Must match your application's domain for all state-changing requests
  • If Origin absent, check Referer header: Use as fallback
  • Reject unexpected origins or missing headers: Strict mode for sensitive operations
  • Use allowlist of permitted origins: Your domains only
  • Ensure validation over HTTPS: Prevent header tampering
  • Implement as additional defense layer: Not as primary protection

Add re-authentication for critical operations

  • For sensitive actions (password changes, fund transfers, account deletion), require password re-entry
  • Implement step-up authentication for high-risk operations
  • Use transaction confirmation mechanisms (email confirmation, 2FA)
  • Add delays or rate limiting for sensitive operations
  • Log all critical actions with full context (IP, user agent, timestamp)

Test and verify CSRF protection thoroughly

  • Test that requests without CSRF tokens are rejected
  • Test that requests with invalid tokens are rejected
  • Test that tokens from different sessions are rejected
  • Create cross-site test page that attempts forged POST request (should fail)
  • Test GET requests cannot perform state changes (should be rejected)
  • Verify SameSite cookies block cross-site requests in browser
  • Test Origin/Referer header validation blocks external requests
  • Ensure AJAX requests include CSRF tokens in headers
  • Test framework CSRF protection is enabled and functioning
  • Verify legitimate forms and AJAX requests still work
  • Re-scan with the security scanner to confirm the issue is resolved
  • Check for any new findings introduced by the changes

Testing and Verification

Manual CSRF Testing

<!-- Create a test page on attacker.com -->
<form action="https://vulnerable-app.com/transfer" method="POST">
  <input type="hidden" name="to_account" value="attacker">
  <input type="hidden" name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>

Expected result: Request should be rejected due to:

  • Missing CSRF token
  • SameSite cookie blocking
  • Origin/Referer validation failure

Test Token Validation

  • Submit request without token → Should fail
  • Submit request with invalid token → Should fail
  • Reuse token from different session → Should fail
  • Submit GET request for state change → Should fail

Verify session cookies have proper attributes:

Set-Cookie: session=...; SameSite=Strict; Secure; HttpOnly; Path=/

Test Framework Protection

  • Verify framework CSRF protection is enabled
  • Test that protection applies to all state-changing endpoints
  • Ensure AJAX requests include CSRF tokens
  • Confirm error handling doesn't leak information

Migration Considerations

IMPORTANT: Adding CSRF protection may break existing integrations and AJAX requests.

What Breaks

  • AJAX requests fail: JavaScript requests without CSRF tokens will be rejected
  • API integrations broken: Third-party integrations or mobile apps calling your endpoints
  • Legacy forms fail: Old HTML forms without CSRF tokens stop working
  • Automated scripts break: Scripts using curl/wget need to include tokens
  • Testing tools fail: Postman, automated tests need updated headers

Migration Approach

Gradual Rollout (Recommended)

  1. Phase 1: Log CSRF violations without blocking

    • Configure application to log failed CSRF validations
    • Don't reject requests yet, just record violations
    • Monitor logs to identify affected endpoints
  2. Phase 2: Add tokens to all forms and AJAX requests

    • Update all HTML forms to include CSRF tokens
    • Configure AJAX libraries to include tokens in headers
    • Test all functionality works with tokens
  3. Phase 3: Enable enforcement (block invalid tokens)

    • Configure application to reject requests without valid tokens
    • Monitor error rates and user reports
    • Be prepared to quickly add exemptions if needed
  4. Phase 4: Monitor and adjust allowlist if needed

    • Review logs for legitimate failures
    • Add API endpoint exemptions as needed
    • Remove temporary exemptions once migration complete

API Exemptions (Use Sparingly)

For legitimate API endpoints that can't use CSRF tokens:

  • Only exempt endpoints using alternative authentication (API keys, OAuth)
  • Never exempt endpoints relying solely on session cookies
  • Document all exemptions and their justification
  • Regularly review exemption list

Rollback Procedures

If CSRF protection breaks functionality:

  1. Disable enforcement temporarily: Use feature flag to revert to logging mode
  2. Add specific exemptions: Allowlist problematic endpoints temporarily
  3. Extend grace period: Keep logging-only mode longer to identify all issues

Testing Recommendations

  • Test all forms include CSRF tokens
  • Test AJAX requests include tokens in headers
  • Test API clients can authenticate without CSRF tokens
  • Test mobile app integration
  • Verify allowlist/exemptions work correctly
  • Load test: CSRF validation performance impact

Language-Specific Guidance

For detailed implementation guidance in specific programming languages and frameworks:

Each language-specific guide includes framework-specific patterns, vulnerable/secure code examples, testing approaches, and common pitfalls to avoid.

Dynamic Scan Guidance

For guidance on remediating this CWE when detected by dynamic (DAST) scanners:

Additional Resources