SSRF Protection

March 30, 2026 · View on GitHub

Server-Side Request Forgery (SSRF) is the primary threat when a database extension makes network requests based on user-supplied URLs. duck_net blocks connections to private and reserved IP ranges by default.

Blocked IP Ranges

IPv4

RangeDescription
127.0.0.0/8Loopback
10.0.0.0/8Private (RFC 1918)
172.16.0.0/12Private (RFC 1918)
192.168.0.0/16Private (RFC 1918)
169.254.0.0/16Link-local / Cloud metadata (169.254.169.254)
100.64.0.0/10Carrier-grade NAT (RFC 6598)
198.18.0.0/15Benchmark testing (RFC 2544)
192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24Documentation (RFC 5737)

IPv6

RangeDescription
::1Loopback
fc00::/7Unique local (RFC 4193)
fe80::/10Link-local
ff00::/8Multicast
2001::/32Teredo (RFC 4380)
2002::/166to4 — also blocked when embedded IPv4 is private
64:ff9b::/96NAT64 (RFC 6146)
2001:db8::/32Documentation (RFC 3849)
::ffff:0:0/96IPv4-mapped — checked for embedded private IPv4

Configuration

-- Check current SSRF protection status
SELECT duck_net_security_status();

-- Disable for local development (NOT recommended for production)
SELECT duck_net_set_ssrf_protection(false);

-- Re-enable
SELECT duck_net_set_ssrf_protection(true);

Redirect-Based SSRF

A common SSRF bypass is to pass an innocuous initial URL that redirects to a private endpoint. duck_net defends against this by handling HTTP redirects manually and revalidating the SSRF policy at each hop:

  1. The initial URL is SSRF-checked before the first request.
  2. Each Location header in a redirect response is parsed and SSRF-checked before following.
  3. A redirect chain of more than 10 hops is terminated with an error.
  4. If any intermediate URL resolves to a blocked address, the entire chain is rejected.

An HTTPS→HTTP downgrade in a redirect chain emits an HTTP_REDIRECT_HTTPS_TO_HTTP HIGH-severity warning.

DNS Rebinding Prevention

DNS rebinding is a TOCTOU (time-of-check/time-of-use) attack: a DNS server returns a public IP for the validation step, then switches to a private IP for the actual connection. duck_net closes this window with SsrfSafeResolver:

  • Before this fix, validate_no_ssrf_host() resolved the hostname once for validation, then ureq resolved it again independently for the connection — leaving a window where a rebinding attack could serve a different address.
  • SsrfSafeResolver implements ureq's Resolver trait and runs inside ureq's connection pipeline. It resolves the hostname once, validates every returned address against the private-IP blocklist, and only then passes the resolved SocketAddr set to the TCP connector — making resolution and validation one atomic step.
  • If any resolved address is private or reserved, the entire request is blocked before the TCP handshake, and ureq performs no second DNS lookup.
  • When SSRF protection is disabled (via duck_net_set_ssrf_protection(false)), SsrfSafeResolver delegates transparently to DefaultResolver so normal resolution proceeds.

CI/Airgapped Systems

For CI pipelines or airgapped environments where you need to reach internal services:

-- Disable SSRF protection for the session
SELECT duck_net_set_ssrf_protection(false);

-- Your internal service calls here
SELECT (http_get('http://internal-api:8080/health')).status;

-- Re-enable before any untrusted input
SELECT duck_net_set_ssrf_protection(true);

Warning: Disabling SSRF protection allows SQL queries to reach any network endpoint, including cloud metadata services (169.254.169.254). Only disable in trusted environments.