On this page
ADR-0025: One SSRF-safe client for user-influenced outbound HTTP
Status: Accepted (WP-01). Implemented in crates/commonlayer-net/src/lib.rs and ranges.rs.
Context
The platform fetches URLs that users influence: outbound webhook endpoints, manifest files from registered repositories, OAuth/OIDC providers. A naive client can be pointed at internal services, cloud metadata endpoints or loopback addresses, directly or via DNS rebinding and redirects.
Decision
commonlayer_net::SafeClient:
- resolves DNS itself and refuses the answer if any address is in a blocked range (loopback, private, link-local, CGNAT, multicast, metadata, IPv6 equivalents and mapped addresses), then pins the connection to the vetted address;
- never follows redirects, rejects credentials in URLs, enforces HTTPS in production, and caps time and response size;
- ignores environment proxy settings, because a proxy would bypass the address checks.
Explicit
allowed_networkscan exempt ranges (tests, private OIDC providers).
Consequences
- Feeds whose canonical URL redirects cannot be fetched; the EPSS default was changed to the FIRST API for this reason (WP-12).
- In environments that only allow egress through a proxy, feed and webhook calls fail by design. In the build sandbox the feed adapters were therefore tested against recorded responses only.
- Payment-provider calls (Stripe) use a regular client because their URL is operator configuration, not user input.