PortSwigger — 2025.10.31

Password Reset Race Condition: PHP Session-Locking Bypass

PortSwigger Race Condition (per-session lock bypass) hard

Platform: PortSwigger Web Security Academy Vulnerability: Race condition in password reset, gated behind PHP per-session request locking


Study the Behavior

Study the password reset process by submitting a password reset for your own account and observe that you’re sent an email containing a reset link. The query string of this link includes your username and a token.

  • Send the POST /forgot-password request to Burp Repeater.
  • In Repeater, send the request a few times, then check your inbox again.
  • Observe that every reset request results in a link with a different token.

Consider the following:

  • The token is of a consistent length. This suggests that it’s either a randomly generated string with a fixed number of characters, or could be a hash of some unknown data, which may be predictable.
  • The fact that the token is different each time indicates that, if it is in fact a hash digest, it must contain some kind of internal state, such as an RNG, a counter, or a timestamp.

  • Duplicate the Repeater tab and add both tabs to a new group. For details on how to do this, see Creating a new tab group.
  • Send the pair of reset requests in parallel a few times. For details on how to do this, see Sending requests in parallel.
  • Observe that there is still a significant delay between each response and that you still get a different token in each confirmation email. Infer that your requests are still being processed in sequence rather than concurrently.

Bypass the Per-Session Locking Restriction

Notice that your session cookie suggests that the website uses a PHP back-end. This could mean that the server only processes one request at a time per session.

  • Send the GET /forgot-password request to Burp Repeater, remove the session cookie from the request, then send it.
  • From the response, copy the newly issued session cookie and CSRF token and use them to replace the respective values in one of the two POST /forgot-password requests. You now have a pair of password reset requests from two different sessions.
  • Send the two POST requests in parallel a few times and observe that the processing times are now much more closely aligned, and sometimes identical.
#race-condition #password-reset #php #session-locking #portswigger #webapp