[·] Boundary Notes
FIELD NOTE 02 / OUTBOUND REQUESTS

Where does the second hop go?

A successful check of the first URL does not authorize a different origin in a redirect.

A believable starting URL

The job is allowed to call https://ledger.example. A URL suggests a routine export and the API returns a redirect to a different service. If the HTTP library follows it automatically, a decision made for the ledger can accidentally authorize a second request elsewhere.

request   https://ledger.example/export/42
response  302 Found
location  https://files.other.example/download/42

These are reserved example names. The lab does not request either one.

Compare parsed origins

Use a URL parser rather than a substring. In the preset, HTTPS and effective port 443 are required, and the hostname must match exactly. The names ledger.example.other.example and ledger.example are different. An authority containing user information is rejected to avoid mistaking the text before the @ for the endpoint.

Set a redirect policy

One safe simplification is to allow no redirects. If they are needed, resolve a relative Location against the previous URL, enforce the policy again on every hop before the connection, keep a small hop limit, and define what happens to authentication headers. The lab checks one optional next hop. It intentionally cannot certify an arbitrarily long redirect chain.

Go beyond the hostname

A hostname rule alone cannot address every SSRF path. DNS answers can change. Check the actual destination addresses against your network policy at connection time, including IPv6 and private infrastructure, and enforce network restrictions outside the application as a second control. An application that accepts a user-supplied destination needs threat modeling beyond this exercise.

Reference: OWASP SSRF Prevention Cheat Sheet.

Reproduce it in the lab ↗