Password reset flaws
“Forgot your password?” is a feature built to let someone get into an account without knowing the password. That is precisely why it is such a tempting target. A strong login page with a weak reset flow is like a vault door next to an unlocked window. Let us learn how to inspect it.
Lab only
Resetting someone else’s password, even to “prove a point”, is account takeover and a criminal offence without authorisation. In this lesson you test the reset feature of your own training application, using accounts you created. In a real engagement, ask beforehand which accounts may be used.
How a reset flow works
A typical, well-designed reset has five steps.
- The user enters their email address or username on the “forgot password” page.
- The application generates a reset token, stores it with an expiry time, and links it to the account.
- It sends an email containing a link with that token to the address registered on the account.
- The user clicks the link, the application verifies the token, and shows a form to choose a new password.
- The password is changed, the token is destroyed, and existing sessions are ended.
The security of the whole process rests on a simple idea: only the legitimate owner of the mailbox can obtain the token. Every flaw in this lesson breaks that idea somewhere.
Flaw 1: the application reveals whether an account exists
If the page answers “No account with this address” for unknown emails and “Email sent” for known ones, it again enables user enumeration, like on the login form. The safe pattern is a single neutral response: “If an account exists for this address, we have sent instructions.” Compare the messages, status codes and response times when you submit an existing and a non-existing address.
Flaw 2: weak or predictable tokens
The token is the key to the account, so it needs to be long, random and generated by a secure random number generator. Problems you might observe:
- Tokens that are short numeric codes with few possible values, which could be guessed within a limited number of tries if nothing restricts attempts.
- Tokens derived from the time, the user’s identifier or a simple hash of the email address.
- Tokens that look different each time but share a visible structure when you request several for different test accounts.
To check, request several reset links for your own test accounts, and compare the tokens. Do you see sequences, repeated parts, or a size that seems small? A strong token has no visible pattern and at least 128 bits of randomness. Record your observations without trying to forge anything for accounts you do not own.
Flaw 3: tokens that live too long or can be reused
A token should have a short lifetime, commonly between a few minutes and an hour, and must work only once. Test in your lab:
- Use a reset link, change the password, then try the same link again. If it still works, the token is reusable.
- Request two links in a row. If the first one remains valid, there are more keys in circulation than necessary. Ideally a new request invalidates the previous one.
- Wait beyond the stated expiry and try again. Does the application enforce it?
Flaw 4: the token is not tied to the account
The reset form usually submits the token, the user and the new password. If the server trusts the user identifier in the request instead of the one linked to the token, an attacker with a valid token for their own account could change the identifier to target another account. This is a flaw of access control (more in chapter 5). In Burp, inspect the final reset request: which fields identify the account? The right design is that the server derives the account only from the token.
Flaw 5: leaking the token
Tokens can leak in several ways:
- In the response. Some applications return the token directly in the HTTP response of the “forgot password” request, perhaps for debugging purposes. Check the response in Burp. If it is there, anyone who requests a reset for any account gets the key without owning the mailbox.
- Through the
Refererheader. If the reset page loads resources from other sites, the browser may pass the URL, including the token, in theRefererheader. Setting a strict referrer policy and using the token once reduces the risk. - In logs and shared devices. Tokens in URLs end up in server logs and browser history, which is why a short life and single use matter.
Flaw 6: links built from untrusted data
Many applications build the reset link using the Host header of the incoming request. If the application trusts it blindly, an attacker could influence the domain written in the email sent to the victim, directing the link to a site under their control. This is known as host header poisoning. The prevention is to build links from a configured, trusted base address rather than from request headers. Testers check whether the link in the email changes when the host-related headers are altered, in the lab.
Flaw 7: weak alternative methods
“Security questions” (your pet’s name, your mother’s maiden name) are often guessable or findable on social networks. Recovery by SMS can be hijacked through number takeover. When several recovery paths exist, the account is only as secure as the weakest one. Modern guidance discourages knowledge-based questions.
Flaw 8: no consequences after reset
After a reset, the application should end other active sessions and notify the owner by email (“your password was changed”). If someone had stolen the old password and held an active session, a reset that leaves it open does not remove them.
A test checklist
| Check | Expected secure behaviour |
|---|---|
| Unknown versus known account | Same neutral message and similar timing |
| Token quality | Long, random, no pattern |
| Token lifetime | Expires quickly |
| Token reuse | Single use, invalidated by a newer request |
| Token binding | Account derived from the token only |
| Token in response | Never; only in the email |
| Link construction | From configuration, not from request headers |
| After reset | Sessions ended, notification email sent |
Tip
In a lab you often have no real mail server. Many training applications show the “email” on screen or write it to a log. Use a local mail catcher on your own machine if you want realism, and keep everything on your isolated network.
Your turn: review a reset flow
Take the reset or password-change feature of your lab application (if it does not have one, use the matching topic of the PortSwigger Web Security Academy). Go through the checklist above, run each test with your own test accounts, and record the result in your notebook with a severity guess.
See a solution
A worked example of notes:
Password reset review (lab application)
- Unknown address: "No such user" vs "Email sent" -> enumeration (medium)
- Token: 6 digits, no visible pattern but tiny search space, no attempt limit (high)
- Lifetime: still valid after 24 hours (medium)
- Reuse: link works a second time after reset (high)
- Token in response body of the forgot-password request (critical)
- After reset: old sessions still active, no notification (low)
Each line becomes a finding with a short recommendation. The critical one is the token in the response: whoever asks for the reset obtains the key, which makes the reset equivalent to having no authentication at all.
Key takeaways
- A reset flow is an alternative way into an account, so it must be at least as strong as the login.
- Tokens must be random, long, short-lived, single-use and tied to the account by the server.
- Never reveal whether an account exists, and never return the token in the web response.
- Build links from trusted configuration, not from request headers.
- End old sessions and notify the owner after a reset.
Because passwords alone are fragile, many applications add a second factor. Let us see how that works and where it can still fail.