The password reset bugs I always test for
Password reset looks like a solved problem and almost never is. Here are the bugs I test for in every reset flow, with no exploit tooling needed.
part ofSecurity testing for QAPassword reset is the flow everyone assumes is fine because it's so common. It's also the flow that, done wrong, hands an attacker someone else's account — which is why it's worth a dedicated pass. The good news for QA: nearly every reset bug is a functional defect you can find with a test inbox and a habit of trying the request twice. This builds on the auth pass in auth bugs QA can catch without being a pentester; here's the reset flow specifically.
1. Is the token single-use?
Request a reset, use the link to set a new password, then click the same link again. It should be dead. If it still works, the token isn't being invalidated on use — which means a reset link sitting in an inbox (or a browser history, or a proxy log) is a permanent backdoor. This is the first thing I test and it fails more often than you'd think.
2. Does the token expire?
Request a reset and don't use the link. Come back the next day (or however long past the stated expiry) and try it. A reset token should expire — an hour, a day, whatever the policy says — and an old one should cleanly say "this link has expired," not silently work or 500. No expiry at all means every reset link ever sent is still live.
3. Does a new request kill the old link?
Request a reset, then request another for the same account before using either. The first link should now be invalid — only the most recent should work. If both work, you've got multiple live tokens floating around, which widens the window for a leaked one to be used.
4. Account enumeration on the request
Submit the reset form for an email that is registered, then for one that isn't. Do the responses differ? "No account with that email" versus "Check your inbox" lets an attacker harvest which emails are valid customers. The correct behaviour is an identical, generic response either way — "if that email exists, we've sent a link" — and the same timing. This is a one-line bug to report and a common finding.
5. Does the reset actually log out the old sessions?
After a successful reset, any session that was already logged in should be invalidated — the whole point is often that the account was compromised. Keep an old session open in another tab, reset the password, then use the old tab. Still logged in? Then resetting the password doesn't actually lock out whoever you were resetting it because of.
6. Can you reset someone else's password?
The dangerous one. When you submit the new password, what ties the request to the account — the token, or something you can tamper with? If the final step includes a user ID or email in the request body that you can change, try changing it to another account. If the server trusts that field instead of the token, you can reset anyone's password. Test it on your own two test accounts: request a reset for A, and at the final step, try to point it at B.
7. Is the new password actually validated?
The reset form should enforce the same password rules as signup — length, complexity, not-the-same-as-old where required. Teams sometimes bolt on the reset flow and forget the validation, so you can reset to 1. Quick check, occasional real bug.
How to report these
Same rules as any auth testing: use test accounts you're authorised to use, never real customer data, and report the defect with expected-vs-actual ("reset link still valid after use; expected single-use") rather than a weaponised writeup. The security testing checklist has the full QA-safe auth pass, and common bugs → auth catalogues these defect classes.
Password reset pass (two test accounts + a test inbox)
- Reset token is single-use (reusing the link after success fails)
- Token expires, and an expired link says so cleanly
- Requesting a new reset invalidates the previous link
- Request response is identical for registered and unregistered emails (no enumeration)
- A successful reset invalidates existing logged-in sessions
- The final step is bound to the token, not a tamperable user-id/email field
- The new password is validated against the same rules as signup
// RELATED QA.CODES RESOURCES
Checklist
Common Bug
// related
Auth bugs QA can catch without being a pentester
The auth and session bugs that show up in normal functional testing — no exploit tooling required.
How to test session expiry properly
A session that lives too long is a hole, one that survives logout defeats the point. Here is the session-expiry pass — idle, absolute, logout, reset, remember-me, and fixation.