CSRF protection for sensitive account changes
Email and password change endpoints accepted cross-origin form posts. Remediated with synchroniser tokens, SameSite cookies, re-authentication and change notification.
Context
An account settings area in a PHP application, reviewed under written authorisation in a staging environment.
Scope
Profile update, email change and password change endpoints, plus the session cookie configuration supporting them.
Vulnerability
State-changing POST requests were accepted without an anti-CSRF token, and the session cookie had no SameSite attribute, so a cross-site form submission executed with the victim's session.
Root cause
CSRF middleware existed but the settings routes had been registered outside the protected route group during a refactor, and no test asserted the protection.
Impact
A victim visiting an attacker-controlled page while logged in could have their account email changed, enabling a password reset takeover. Rated Medium because it needed user interaction, but the outcome was account takeover.
Remediation
- Returned the settings routes to the CSRF-protected group and removed the ability to register unprotected web routes.
- Set
SameSite=Lax,SecureandHttpOnlyon the session cookie. - Required current-password re-authentication for email and password changes.
- Sent a notification to the previous address on any email change, with a revocation link.
- Added tests asserting that a POST without a valid token returns 419 for every state-changing route.
Retesting
Retesting submitted the original cross-origin form, a token from another session, an expired token and a request with the token omitted entirely. All were rejected. Legitimate changes continued to work, and the notification e-mail was observed on the previous address.
Lessons
- Protection applied by route group is only as reliable as the discipline of route registration; assert it in tests.
- CSRF defences pair well with re-authentication for high-value actions.
- Notifying the old address is what turns a silent takeover into a detected one.
Authorisation
This work was carried out under written authorisation or inside an authorised training environment. All evidence has been sanitised.
Continue reading
Related case studies
IDOR: missing server-side authorisation in an invoice workflow
An authenticated user could modify an invoice identifier and attempt to access another customer's resource. The remediation enforced ownership at the database query layer and was verified with positive and negative authorisation tests.
5 min read
Secure payment webhooks: validating PayPal, Stripe and Flutterwave callbacks
A secure payment integration case study covering server-side verification, webhook authenticity, payment-state validation, duplicate processing, secrets management and safe failure handling.
8 min read
SSRF in a server-side document import feature
An authorised security lab examining how a user-controlled URL can cause a web server to make unintended requests to internal or restricted destinations, followed by layered remediation and retesting.
9 min read