# CSRF token is not bound to the user session

- **ID:** `security/csrf-token-not-bound-to-session`
- **Domain:** security
- **Category:** auth_error
- **Error Code:** `CSRFValidationException`
- **Verification:** ai_generated
- **Fix Rate:** 90%

## Root Cause

The CSRF token is generated globally or per-request but not tied to the session, allowing an attacker to predict or reuse a token across sessions.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| Django 4.2 | active | — | — |
| Spring Security 5.7 | active | — | — |
| Flask-WTF 1.1 | active | — | — |
| Express.js | active | — | — |

## Workarounds

1. **Store the CSRF token in the session and generate a random value per session. Example (Python Flask): `session['csrf_token'] = secrets.token_hex(32)` and compare it in the view.** (95% success)
   ```
   Store the CSRF token in the session and generate a random value per session. Example (Python Flask): `session['csrf_token'] = secrets.token_hex(32)` and compare it in the view.
   ```
2. **Use a framework's built-in CSRF protection, such as Django's `{% csrf_token %}` or Spring Security's `CsrfTokenRepository` with `HttpSessionCsrfTokenRepository`.** (90% success)
   ```
   Use a framework's built-in CSRF protection, such as Django's `{% csrf_token %}` or Spring Security's `CsrfTokenRepository` with `HttpSessionCsrfTokenRepository`.
   ```
3. **Implement double-submit cookies: generate a random token, set it as a cookie, and include it in a hidden form field; verify both match on the server.** (85% success)
   ```
   Implement double-submit cookies: generate a random token, set it as a cookie, and include it in a hidden form field; verify both match on the server.
   ```

## Dead Ends

- **** — Using a static CSRF token for all users doesn't fix the issue; it makes the token easily guessable. (80% fail)
- **** — Only checking the token's presence, not its value, leaves the application vulnerable to token fixation. (70% fail)
- **** — Regenerating the token on every request without storing it in the session causes validation failures. (60% fail)
