Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type Race Conditions
Difficulty Practitioner
Objective Exploit a race condition in the email change endpoint to associate carlos@ginandjuice.shop with our account, inherit admin privileges, and delete carlos

Single-Endpoint Race Conditions

I logged in as wiener:peter and tested the email change flow:

Screenshot
Screenshot
Screenshot

I duplicated the request 20 times with different addresses (teto1@exploit through teto20@exploit) and sent the group sequentially first to establish a baseline:

Screenshot

Each address received exactly the confirmation email corresponding to its own change request — normal behavior:

Screenshot

Benchmarking sequential vs parallel is how you find single-endpoint race windows. Sequential sends produce correct, correlated results; parallel sends surface anomalies. Sending the same group in parallel:

Screenshot
Screenshot

An email sent to teto16@exploit contained a confirmation link for teto20@. Recipient and confirmed address didn't match. The race condition is inside the email send operation itself — the server writes the email body (including the target email in the confirmation link) and the TO field in two separate steps. Parallel requests interleave these writes: one request's body is paired with another request's recipient. Email-based operations are disproportionately vulnerable to this because emails are often sent in a background thread after the HTTP response, extending the race window beyond the normal request lifecycle.

Weaponizing this desync with two parallel requests:

  • Request 1: email=tetohack@exploit-...exploit-server.net (our inbox — we receive it)
  • Request 2: email=carlos@ginandjuice.shop (the target address we want to claim)
Screenshot

Repeated until the race fired — the server wrote the carlos@ginandjuice.shop payload into the body but delivered it to our inbox:

Screenshot
To confirm your email change to carlos@ginandjuice.shop, click the link below

The confirmation link remains valid across attempts, so each retry doesn't reset state. Clicking the link:

Screenshot

Account email now shows carlos@ginandjuice.shop. The pending admin invite activated. Navigating to /admin and deleting carlos:

Screenshot

Lab solved

Resources