In SSRF (especially blind SSRF), one of the most important questions isn’t just β€œDid I get a callback?” β€” it’s how the fetching client behaves.
If that client follows redirects, it can be the difference between a β€œlimited” SSRF and an SSRF with bypass potential or greater reach.

Introspector detects this passively by leveraging a common real-world pattern: many clients (workers, headless browsers, link preview bots, document parsers) automatically request /favicon.ico when they touch a domain.


Why redirect-following matters in SSRF

When a backend follows 301/302:

  • Allowlist bypass potential: some implementations validate only the initial URL (e.g., β€œonly allow trusted domains”), but fail to enforce controls after a redirect.
    If redirects are followed, you may β€œenter” via an allowed domain and end up at a different final destination.

  • Redirect chaining: attacker-controlled intermediate endpoints can be used to:
    • measure client behavior,
    • dynamically adjust the final destination,
    • and steer requests based on what you observe (without relying on the target’s response).
  • Better fetcher fingerprinting: whether redirects are followed strongly indicates if you’re dealing with:
    • a real headless browser,
    • a link preview bot,
    • a strict HTTP library / worker,
    • or a component that only resolves/validates.

In short: redirect-following often increases what an SSRF can reach.


How Introspector validates it (passively)

When a client hits introspector.sh/favicon.ico, Introspector replies with a 302 to a verification endpoint:

  • GET /favicon.ico (302 β†’ /favicon-followed)

If the client follows the redirect, it will request /favicon-followed.
At that moment Introspector marks the event with FOLLOW REDIRECT (clear evidence that the fetcher follows redirects).

Then, to avoid loops and keep the flow realistic, /favicon-followed redirects once more:

  • GET /favicon-followed (302 β†’ /index.ico)

Passive Redirect Check

                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚   SSRF Client / Bot / Worker  β”‚
                      β”‚  (headless, preview, parser)  β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                                      β”‚ 1) GET /favicon.ico
                                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚          Introspector (HTTP Listener)           β”‚
            β”‚ responds with: 302 Location β†’ /favicon-followed β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚       follows redirect?     β”‚
                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚                                       β”‚
                β–Ό                                       β–Ό
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ 2) GET /favicon-followed         β”‚   β”‚ No second request observed       β”‚
 β”‚ Introspector flags:              β”‚   β”‚ β†’ likely no redirect support     β”‚
 β”‚   βœ… FOLLOW REDIRECT             β”‚   β”‚ β†’ use other SSRF techniques      β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                     β”‚ 2.5) 302 Location β†’ /index.ico
                     β–Ό
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚ 3) GET /index.ico (final)        β”‚
        β”‚ Evidence remains in logs:        β”‚
        β”‚ timestamps, headers, IP, path    β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜