Preflight checklist
Ory Network Project
No response
Describe the bug
The recovery flow with code strategy never reaches the max submissions check because the CSRF token becomes stale after failed code submissions. When users exceed the max submission limit (default 5), the 6th attempt fails with a 403 CSRF error instead of returning 410 Gone (as the verification flow does).
Root cause:
- CSRF validation happens before the max submissions check in strategy_recovery.go:178
- By the 6th attempt, the CSRF token is stale/invalid, causing CSRF validation to fail first
- The max submissions check (which would return 400/410) never executes because CSRF fails earlier
Reproducing the bug
- Initiate a recovery flow with code strategy
- Submit 5 incorrect recovery codes (attempts 1-5)
- On the 6th attempt, submit another incorrect code
- Observe the response
Expected: 410 Gone status with use_flow_id in the response (new flow created)
Actual: 403 Forbidden status with CSRF error message: "the request was rejected to protect you from Cross-Site-Request-Forgery"
Code flow:
strategy_recovery.go:178 - CSRF check happens first
strategy_recovery.go:197 - recoveryUseCode() is called (only if CSRF passes)
strategy_recovery.go:344 - Max submissions check happens inside UseRecoveryCode()
Since CSRF fails at line 178, line 344 is never reached
Relevant log output
[Log]
{
error: "the request was rejected to protect you from Cross-Site-Request-Forgery"
}
Relevant configuration
selfservice:
methods:
code:
enabled: true
config:
passwordless_enabled: false
Version
25.4.0
On which operating system are you observing this issue?
None
In which environment are you deploying?
None
Additional Context
No response
Preflight checklist
Ory Network Project
No response
Describe the bug
The recovery flow with code strategy never reaches the max submissions check because the CSRF token becomes stale after failed code submissions. When users exceed the max submission limit (default 5), the 6th attempt fails with a 403 CSRF error instead of returning 410 Gone (as the verification flow does).
Root cause:
Reproducing the bug
Expected: 410 Gone status with use_flow_id in the response (new flow created)
Actual: 403 Forbidden status with CSRF error message: "the request was rejected to protect you from Cross-Site-Request-Forgery"
Code flow:
strategy_recovery.go:178 - CSRF check happens first
strategy_recovery.go:197 - recoveryUseCode() is called (only if CSRF passes)
strategy_recovery.go:344 - Max submissions check happens inside UseRecoveryCode()
Since CSRF fails at line 178, line 344 is never reached
Relevant log output
[Log] { error: "the request was rejected to protect you from Cross-Site-Request-Forgery" }Relevant configuration
Version
25.4.0
On which operating system are you observing this issue?
None
In which environment are you deploying?
None
Additional Context
No response