Authorization disclaimer. This walkthrough is exclusively for the intentionally vulnerable PortSwigger Web Security Academy lab linked below. Only test systems you own or are explicitly authorized to assess.

Overview

Changing the account identifier to carlos triggers a 302 Found response, so a browser appears to deny access by immediately following the redirect. However, the original response body has already been populated with Carlos’s account data, including the synthetic API key.

The exercise identifies the redirect body as the disclosure point and supplies `wiener:peter` for retrieving Carlos's API key.
The exercise identifies the redirect body as the disclosure point and supplies `wiener:peter` for retrieving Carlos's API key.

Lab objective/setup

Sign in with wiener:peter, obtain the synthetic API key belonging to carlos, and submit it through the lab interface.

What I observed

The account page used GET /my-account?id=wiener. Replacing the identifier with carlos caused the browser to leave the page, which initially looked like successful enforcement. Inspecting the exchange in Burp Repeater showed the important detail: the 302 response still contained the unauthorized account HTML.

The normal account is selected by the query string `/my-account?id=wiener`, exposing the identifier that can be changed.
The normal account is selected by the query string `/my-account?id=wiener`, exposing the identifier that can be changed.
Although navigation is redirected, the original HTML body already contains the `carlos` username and a complete API key.
Although navigation is redirected, the original HTML body already contains the `carlos` username and a complete API key.
The browser lands on `/login` after following the redirect, concealing the sensitive body from the preceding `302 Found` response.
The browser lands on `/login` after following the redirect, concealing the sensitive body from the preceding `302 Found` response.

Why it is vulnerable

A redirect is navigation metadata, not an authorization boundary. The application renders sensitive data before deciding to redirect, and HTTP clients can always inspect the first response. An unauthorized request must be rejected before protected data is loaded or serialized.

Walkthrough in the authorized PortSwigger lab

  1. Log in as wiener and capture the account request.
  2. Send it to Repeater and change the id parameter to carlos.
  3. Do not follow the redirect automatically; inspect the body of the 302 response.
  4. Copy the synthetic API key present in that body and submit it to the lab.
Repeater preserves the first response: `GET /my-account?id=carlos` returns `302 Found` to `/login` while still delivering account HTML below the headers.
Repeater preserves the first response: `GET /my-account?id=carlos` returns `302 Found` to `/login` while still delivering account HTML below the headers.
The Academy marks the redirect-leak lab solved after the API key extracted from the `302` body is submitted.
The Academy marks the redirect-leak lab solved after the API key extracted from the `302` body is submitted.

Verification

The unauthorized request returns a redirect, yet its raw body contains Carlos’s data. Successful submission of the included lab key confirms that the leak occurs before the redirect is followed.

Impact and defensive lesson

This pattern can expose API keys, personal records, or account metadata while remaining invisible in ordinary browser navigation. Perform authorization before fetching or rendering an object, return a minimal error response, and test raw redirect bodies during security reviews.

References