parlov docs

Forcing 3xx Redirects

Many web servers enforce a canonical URL form, and the server often must resolve the resource before it can determine the canonical form and issue the redirect.

Implemented

Mechanism: Many web servers enforce a canonical URL form — trailing slashes, case normalization, or path segment normalization. The server often must resolve the resource before it can determine the canonical form and issue the redirect. For non-existing resources, there's nothing to canonicalize — the server returns 404.

Common canonicalization patterns:

  • Trailing slash enforcement: /api/users/1001301 to /api/users/1001/ (or vice versa)
  • Case normalization: /API/Users/1001301 to /api/users/1001
  • Index resolution: /api/users/1001301 to /api/users/1001/index

Isolated Variable: Only the path format changes. Method, headers, body, and authentication remain identical.

Oracle Signal: 301/302 (exists, server redirects to canonical form) vs 404 (does not exist).

GET — Existing Resource (Trailing Slash Added)

GET /api/users/1001/ HTTP/1.1
Host: target.com
Authorization: Bearer valid-token

HTTP/1.1 301 Moved Permanently
Location: /api/users/1001
Content-Type: text/html

<html><body>Moved to /api/users/1001</body></html>

GET — Non-Existing Resource (Trailing Slash Added)

GET /api/users/9999/ HTTP/1.1
Host: target.com
Authorization: Bearer valid-token

HTTP/1.1 404 Not Found
Content-Type: application/json

{"error": "Not Found"}

GET — Existing Resource (Wrong Case)

GET /API/USERS/1001 HTTP/1.1
Host: target.com
Authorization: Bearer valid-token

HTTP/1.1 301 Moved Permanently
Location: /api/users/1001

GET — Non-Existing Resource (Wrong Case)

GET /API/USERS/9999 HTTP/1.1
Host: target.com
Authorization: Bearer valid-token

HTTP/1.1 404 Not Found
Content-Type: application/json

{"error": "Not Found"}

💡 Location header as a secondary oracle: The Location header reveals the server's canonical URL. Different resource types may have different canonical forms — comparing Location values across resource IDs reveals resource type or category.

💡 Route-level vs resource-level redirects: Some redirects happen at the route level (all paths get normalization regardless of the specific resource) and produce no oracle. Test by comparing: if both valid and invalid IDs redirect, the redirect is route-level. If only valid IDs redirect, the oracle is confirmed.

💡 Double-slash and dot-segment normalization: Beyond trailing slashes, test: /api/users//1001, /api/users/1001/./profile, /api/users/1001/../1001, /api/users/1001%2Fprofile. Each is a potential oracle if the server resolves the resource before normalizing.

Mitigation: Perform path canonicalization at the routing layer before resource resolution. Return the same redirect (or the same 404) for both existing and non-existing resources under the same route pattern.