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

Overview

The application exposes interactive API documentation at /api. The documentation reveals a user-deletion operation, and the backend allows the authenticated wiener account to delete the separate carlos account without an adequate authorization check.

The lab requires finding documentation at `GET /api` and deleting `carlos` while authenticated as `wiener`.
The lab requires finding documentation at `GET /api` and deleting `carlos` while authenticated as `wiener`.

Lab objective/setup

Sign in with the supplied wiener:peter credentials, discover the API documentation, and use the documented interface to delete carlos.

What I observed

Updating the email address on the account page generated API traffic visible in Burp. The browser workflow reached PATCH /api/user/wiener, establishing both the /api prefix and the resource pattern.

The `wiener` account page exposes an email update action suitable for capturing API traffic.
The `wiener` account page exposes an email update action suitable for capturing API traffic.
Burp records the authenticated account workflow preceding `PATCH /api/user/wiener`.
Burp records the authenticated account workflow preceding `PATCH /api/user/wiener`.
The browser confirms that the email update to `test@example.com` succeeded.
The browser confirms that the email update to `[email protected]` succeeded.
`PATCH /api/user/wiener` returns `200 OK` with the updated user JSON, revealing the API resource pattern.
`PATCH /api/user/wiener` returns `200 OK` with the updated user JSON, revealing the API resource pattern.
The captured `PATCH /api/user/wiener` request is moved to Repeater for parent-path discovery.
The captured `PATCH /api/user/wiener` request is moved to Repeater for parent-path discovery.

Testing parent paths in Repeater showed that /api/user was not a valid collection route, while GET /api returned HTML for an interactive documentation page.

Removing the username from `PATCH /api/user/wiener` produces `400 Malformed URL`, showing that the route requires an identifier.
Removing the username from `PATCH /api/user/wiener` produces `400 Malformed URL`, showing that the route requires an identifier.
Changing the collection probe to `GET /api/user` still returns the identifier error.
Changing the collection probe to `GET /api/user` still returns the identifier error.
`GET /api` returns `200 OK` with HTML, confirming an exposed documentation page at the API root.
`GET /api` returns `200 OK` with HTML, confirming an exposed documentation page at the API root.

Why it is vulnerable

Two conditions combine here. First, production-accessible documentation discloses operations and parameter formats that the main interface does not advertise. Second, the documented DELETE /api/user/{username} handler accepts a username from the path without adequately ensuring that the current session may delete that account. Documentation exposure accelerates discovery; missing object-level authorization enables the destructive action.

Walkthrough in the authorized PortSwigger lab

  1. Log in as wiener and update the email address while Burp records traffic.
  2. Send PATCH /api/user/wiener to Repeater and progressively test the parent paths.
  3. Request GET /api and open the returned interactive documentation in the browser.
  4. Locate DELETE /api/user/{username}, enter carlos, and execute the documented operation.
The documentation enumerates `DELETE /api/user/{username}` alongside the read and email-update operations.
The documentation enumerates `DELETE /api/user/{username}` alongside the read and email-update operations.
The documentation toolkit builds `DELETE /api/user/carlos` from the supplied username.
The documentation toolkit builds `DELETE /api/user/carlos` from the supplied username.
`DELETE /api/user/carlos` returns `200` with `{"status":"User deleted"}`, confirming the unauthorized deletion.
`DELETE /api/user/carlos` returns `200` with `{"status":"User deleted"}`, confirming the unauthorized deletion.

Verification

The delete operation returns successfully and the Academy marks the lab solved. The request is performed in wiener‘s session but targets carlos, demonstrating that authentication alone did not enforce permission over the selected user object.

Impact and defensive lesson

An equivalent flaw in a real service could let ordinary users destroy or modify other accounts. Exposed documentation also reduces the effort required to inventory sensitive or legacy operations.

  • Enforce object-level authorization on every request, including destructive endpoints.
  • Derive self-service account identity from the authenticated principal where possible rather than a client-controlled path value.
  • Restrict administrative deletion to explicitly authorized roles and record auditable events.
  • Remove, authenticate, or network-restrict interactive documentation in production according to operational need.
  • Maintain an accurate API inventory and test documented and undocumented versions consistently.

References

Provenance

Adapted and rewritten in English from the private migration source declared in the front matter. Technical observations and screenshots are retained from that authorized PortSwigger lab session; no behavior beyond the source evidence is asserted.