The Hidden Danger in Redirects

Server-Side Request Forgery (SSRF) remains a persistent threat, often exploited by chaining seemingly innocuous actions. A common blind spot occurs when a URL fetcher, initially presented with a legitimate public address, is silently redirected to a private network resource. This happens because many services treat the initial DNS resolution as the sole point of trust. The application approves the public hostname, but the server responds with a redirect to an internal IP, such as a metadata service endpoint (e.g., http://169.254.169.254/latest/meta-data/).

This is not a vulnerability in a specific framework but a fundamental gap in how URL fetchers handle network destinations. A URL, after all, is not a single network destination. DNS records can change, and redirects explicitly introduce new targets. An initially public hostname can resolve to private IP space, bypassing perimeter defenses that only checked the first hop.

The invariant proposed to counter this is stricter: Every connection attempt must target an address allowed by policy, and every redirect must receive a new authorization decision. This means the decision point must be invoked not just on the initial URL but on every subsequent redirect. This pattern aims to build that robust decision point into the fetching process.

Understanding the Trust Boundary

The core issue lies in the trust boundary. When a user submits a URL, the application typically performs a DNS lookup. If the DNS resolution points to a public IP address, the application often grants permission for the request to proceed. However, the server at that public IP can respond with an HTTP redirect (e.g., a 301 or 302 status code). If the fetch client automatically follows this redirect, it may then connect to a private IP address that was never vetted. This is akin to a security guard checking IDs at the main gate, only for the person to be immediately directed inside to a restricted area without further checks.

Consider a URL preview service. A user submits https://example.com/report. The DNS lookup for example.com returns a public IP. The service, seeing a public IP, allows the request. The server at example.com, however, is configured to redirect all requests to http://169.254.169.254/latest/meta-data/. A default fetch client will follow this redirect. The subsequent request to 169.254.169.254, a standard IP for cloud instance metadata services, now has direct access to sensitive instance information, bypassing the initial public-facing check.

Diagram illustrating a redirect chain from a public IP to a private metadata service IP

Implementing the Stricter Invariant

To build a more secure URL fetching mechanism, developers must implement a policy check at each step of a potential redirect chain. This involves modifying the behavior of the URL fetcher to intercept and re-evaluate every redirect response before automatically following it.

The process should look like this:

  1. Initial Request: The application receives a user-provided URL.
  2. DNS Resolution & Policy Check: Perform a DNS lookup. Before making any connection, check if the resolved IP address is allowed by the application's policy. Policies should explicitly define which IP ranges (public, private, specific internal IPs) are permissible targets. If the IP is not allowed, reject the request.
  3. Connection & Response Handling: If the IP is allowed, establish a connection and receive the response.
  4. Redirect Interception: If the response is a redirect (e.g., 3xx status code), do NOT automatically follow it. Instead, extract the new URL from the Location header.
  5. Re-authorization: Treat the new URL from the redirect as a completely new request. Perform a DNS lookup for this new URL. Then, apply the same policy check (step 2) to the newly resolved IP address.
  6. Conditional Follow: Only if the new IP address is also allowed by policy should the fetcher proceed to make a request to that new destination. If the new URL resolves to a disallowed IP, reject the request.
  7. Final Data Fetch: If the connection is to an allowed IP and is not a redirect, the content can be fetched and processed.

This iterative authorization process ensures that no redirect can silently bypass security controls and point to an unintended, potentially sensitive, network destination. It shifts the trust model from a one-time check to a continuous verification at every network hop introduced by redirects.

Why This Matters for Developers and Services

This pattern is critical for any service that fetches external URLs on behalf of users or processes user-submitted links. This includes, but is not limited to:

  • URL preview services
  • Web scrapers and data import tools
  • Content aggregation platforms
  • Link shortener expanders
  • Any application interacting with user-provided URIs

Failing to implement this stricter check means these services become prime targets for SSRF attacks. An attacker could craft a malicious URL that, when processed by the vulnerable service, leads to the service making requests to internal services, cloud metadata endpoints, or other sensitive network resources. The consequences can range from information disclosure to unauthorized actions within the internal network.

The surprising detail here is not the existence of redirects, but how universally the security decision is tied *only* to the initial DNS resolution, ignoring the dynamic nature of network addressing in modern web protocols. By re-authorizing each hop, developers close a significant attack vector that often goes unaddressed.

Broader Implications

This defensive strategy highlights the need for a more granular understanding of network access control in application development. It’s not enough to control what external hosts an application can resolve; one must control where it can *connect*. Redirects blur this line, and the proposed pattern addresses this by treating each redirect as a new connection attempt requiring fresh authorization. Building this into libraries and frameworks could significantly raise the bar for SSRF attacks, forcing attackers to find more complex or less common exploitation vectors. If you run a team that processes external URLs, you should review your fetcher implementations immediately to ensure they are not silently following redirects into potentially private network space.