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

The front-end component blocks requests whose visible URL begins with /admin, but the backend honors X-Original-URL when selecting a route. Supplying an innocuous request target while placing the protected path in that header makes the two layers enforce different URLs.

The lab identifies a split between the blocked `/admin` path and backend routing through `X-Original-URL`, with deletion of `carlos` as the goal.
The lab identifies a split between the blocked `/admin` path and backend routing through `X-Original-URL`, with deletion of `carlos` as the goal.

Lab objective/setup

Reach the administrative functionality and delete the synthetic user carlos. The lab hint identifies X-Original-URL as a header worth testing.

What I observed

The application exposed an admin link, but a direct request to /admin returned an unauthorized response. Sending a request to / with X-Original-URL: /admin instead returned the administration panel, demonstrating that the backend used the header for routing after the front end had inspected the request line.

The storefront advertises an `Admin panel` link even though the upstream control prevents ordinary access to that route.
The storefront advertises an `Admin panel` link even though the upstream control prevents ordinary access to that route.
A normal request for `/admin` is rejected with `Access denied`, establishing the front-end URL restriction.
A normal request for `/admin` is rejected with `Access denied`, establishing the front-end URL restriction.
With the request line set to `/` and `X-Original-URL: /admin`, the backend returns the admin HTML containing `/admin/delete?username=carlos`.
With the request line set to `/` and `X-Original-URL: /admin`, the backend returns the admin HTML containing `/admin/delete?username=carlos`.

Why it is vulnerable

Authorization is applied to one representation of the URL while routing uses another. Because the client can supply the override header, a request may pass the proxy’s path rule and still reach a privileged backend handler. Access control must be based on a single normalized route and repeated at the application endpoint.

Walkthrough in the authorized PortSwigger lab

  1. Confirm that requesting /admin directly is denied.
  2. Send a request to / with X-Original-URL: /admin to establish the parsing discrepancy.
  3. Keep the visible target outside /admin, place the action path in the header, and carry the username in the query string:
1
2
GET /?username=carlos HTTP/1.1
X-Original-URL: /admin/delete
  1. Replay the request inside the lab session.
Keeping `/admin/delete?username=carlos` in the request line triggers the front-end rule and produces `403 Forbidden` with `Access denied`.
Keeping `/admin/delete?username=carlos` in the request line triggers the front-end rule and produces `403 Forbidden` with `Access denied`.
Moving `username=carlos` to the benign request target and setting `X-Original-URL: /admin/delete` reaches the delete handler, which responds `302 Found`.
Moving `username=carlos` to the benign request target and setting `X-Original-URL: /admin/delete` reaches the delete handler, which responds `302 Found`.
The Academy changes the URL-based access-control lab to solved after the header-routed deletion request succeeds.
The Academy changes the URL-based access-control lab to solved after the header-routed deletion request succeeds.

Verification

The same account is denied when /admin appears in the request line but receives the panel when the path is supplied through X-Original-URL. The Academy marks the lab solved after the header-based delete request.

Impact and defensive lesson

In a real system, this discrepancy could expose every route protected only by an upstream URL rule. Strip untrusted rewrite headers at the edge, normalize paths consistently, and enforce authorization in each backend handler rather than relying solely on proxy filtering.

References