Authorization disclaimer. This walkthrough is limited to the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Test only systems you own or are explicitly authorized to assess.

Overview

The reset workflow accepts a valid reset page but does not reliably bind the submitted new password to the account that requested the reset.

The Academy brief names Carlos as the victim and requires resetting his password before opening his My Account page.
The Academy brief names Carlos as the victim and requires resetting his password before opening his My Account page.

Lab objective/setup

The supplied credentials, candidate lists, email client, and exploit server are used only inside this Academy instance to reproduce the authentication-flow evidence shown below.

What I observed

The final reset request carries both a valid token and a separate username body field. Changing that field from Wiener to Carlos while retaining Wiener’s token resets Carlos’s password.

At `/my-account?id=wiener`, the authenticated page for Wiener establishes the attacker-controlled account used to request a legitimate reset token.
At `/my-account?id=wiener`, the authenticated page for Wiener establishes the attacker-controlled account used to request a legitimate reset token.
The forgot-password form is filled with Wiener's email address, initiating a reset for the controlled account.
The forgot-password form is filled with Wiener's email address, initiating a reset for the controlled account.

Why it is vulnerable

A reset token must be tied server-side to one account, purpose, and expiry; user-controlled identity fields cannot decide the reset target.

Walkthrough in the authorized PortSwigger lab

Request and open a reset link for Wiener, intercept the final password submission, change only username=wiener to username=carlos, and submit. The redirect is followed by a successful Carlos login with the chosen password.

The email client shows a reset link containing a `temp-forgot-password-token` issued for Wiener.
The email client shows a reset link containing a `temp-forgot-password-token` issued for Wiener.
Opening that link displays the new-password and confirmation fields, showing the token has reached the final reset form.
Opening that link displays the new-password and confirmation fields, showing the token has reached the final reset form.
Burp history shows the reset submission includes both the URL token and a separate body field `username=wiener`.
Burp history shows the reset submission includes both the URL token and a separate body field `username=wiener`.
The `POST /forgot-password` reset request retains the valid token issued for Wiener but changes the body to `username=carlos` and receives a `302 Found` response.
The `POST /forgot-password` reset request retains the valid token issued for Wiener but changes the body to `username=carlos` and receives a `302 Found` response.

Verification

The final capture shows the Academy marking the password reset broken logic exercise as solved after the documented request sequence. No testing was performed outside the isolated lab.

The `/my-account?id=carlos` result is the account page for Carlos, displayed after login with the newly assigned password, confirming the token was not bound to its original username.
The `/my-account?id=carlos` result is the account page for Carlos, displayed after login with the newly assigned password, confirming the token was not bound to its original username.

Impact and defensive lesson

Authentication controls must bind identity, challenge state, reset tokens, and retry counters to server-side transactions. Return uniform failures, rate-limit by both account and trusted client signals, and use random revocable persistent-session tokens rather than credential-derived values.

References