DEV Community

Cover image for The 403 Bypass Playbook: Path Normalization and Reverse-Proxy Discrepancies
Mohamed
Mohamed

Posted on

The 403 Bypass Playbook: Path Normalization and Reverse-Proxy Discrepancies

A 403 is rarely the end of the story. Here's the playbook senior testers run when an endpoint says Forbidden.

You find a juicy endpoint during recon:

GET /admin/dashboard ➔ 403 Forbidden

Most people close the tab and move on. Senior testers treat a 403 as an invitation to test parser discrepancy — because modern apps aren't one monolith. They sit behind edge gateways, WAFs and reverse proxies (Cloudflare, Nginx, HAProxy, Envoy) that route to backends (Node, Spring Boot, Flask, Go). When the proxy and the backend parse a URL differently, the auth gate falls apart.

1. Path normalization quirks

The proxy inspects the raw URI; the backend normalizes it:

GET /admin/..;/dashboard
GET /admin/./dashboard
GET /admin/..%2f/dashboard
GET /admin;/dashboard
Enter fullscreen mode Exit fullscreen mode

Nginx sees /admin/..;/dashboard as not matching the /admin ACL block, while a Tomcat/Spring backend strips /..;/ and serves the protected controller.

2. Reverse-proxy header overrides

Many internal stacks trust legacy routing headers:

GET / HTTP/1.1
Host: target.com
X-Original-URL: /admin/dashboard
X-Rewrite-URL: /admin/dashboard
X-Forwarded-Prefix: /admin
Enter fullscreen mode Exit fullscreen mode

The WAF sees a benign request to /. The backend reads X-Original-URL, rewrites the internal route, and runs the admin logic.

3. Verb tampering and method override

Access control is often tied to a single method:

GET  /admin/users  ➔ 403
POST /admin/users  ➔ 200
HEAD /admin/users  ➔ 200
Enter fullscreen mode Exit fullscreen mode

...or via override headers like X-HTTP-Method-Override: GET and a _method=PUT body field.

4. Case and extension tricks

GET /Admin/Dashboard
GET /admin/dashboard.json
GET /admin/dashboard/.
GET /admin/dashboard?x=1
Enter fullscreen mode Exit fullscreen mode

How to actually fix it

  • Normalize before you inspect. Canonicalize and decode the path before evaluating ACLs at the edge.
  • Strip client-supplied routing headers (X-Original-URL, X-Rewrite-URL, X-Forwarded-*) at the ingress boundary so nobody can inject them.
  • Zero-trust the backend. Never rely only on the edge gateway. Every service validates identity and role on the controller itself.

Ever unlocked a critical finding through path normalization? Share your favourite bypass below.

Top comments (0)