ssrf-guard

Security model

ssrf-guard is four independent gates, each closing a different SSRF bypass. Read this to know what each gate guarantees, where it doesn’t, and what you still need to think about.

The four gates

Gate When What it checks Failure mode
SsrfGuardInterceptor Before DNS URL scheme, host (whitelist match), port SecurityException
SafeDnsResolver (whitelist) At DNS resolution Host (whitelist match again) UnknownHostException
SafeDnsResolver (IP filter) At DNS resolution Each resolved IP is not in private/loopback/link-local/multicast/CGNAT/benchmark/IPv6-ULA UnknownHostException if nothing left after filter
SafeRedirectStrategy On every 3xx Re-runs scheme + DNS-resolver against the redirect target RedirectException

Each gate runs even if the others have already passed — defense in depth. An attacker has to bypass every layer to land an outbound call.

Why the whitelist is checked twice

The naïve “check the URL once, then make the request” pattern has a race condition:

  1. App parses URL, extracts host
  2. App checks whitelist on the host string
  3. App passes URL to HTTP client
  4. HTTP client resolves DNS — gets back a different IP than the host implies
  5. Connection happens to that different IP

Between (2) and (4) the URL string changes meaning. ssrf-guard solves this two ways:

That’s the “TOCTOU mitigation” line in the project description.

What block-private-networks blocks

Set to true by default. Resolves matching any of:

Java’s built-in InetAddress.isSiteLocalAddress() misses CGNAT, the benchmark range, and most of the IPv6 categories — NetUtil.isPrivateOrLocal() is hand-rolled to cover all of them.

What ssrf-guard does NOT do

Honest list. Knowing the boundary is part of the threat model.

Threat-model checklist

If you’re using ssrf-guard, you should also:

  1. Run with block-private-networks=true unless you have a specific reason to allow internal calls. The default is true precisely because turning it off is the most common way to accidentally re-enable SSRF.
  2. Keep follow-redirects=true unless you have a specific reason to forbid redirects. Disabling redirects is sometimes a defense in depth move but it tends to break legitimate API integrations.
  3. Treat the whitelist as security-critical config. Anyone who can write to it can effectively bypass ssrf-guard. Run config diffs through code review.
  4. Don’t let your URL come from a string concat with user input. Even with ssrf-guard active, https://api.partner.com/proxy?target= + user-supplied URL is its own SSRF (you become the attacker’s proxy). Validate the user-supplied URL before composing.
  5. Monitor for SecurityException: Host not allowed in logs. Either it’s an attacker probing, or it’s a legitimate integration that needs a whitelist update.

The OWASP SSRF prevention cheat sheet is worth re-reading every six months.