PATTERN Cited by 1 source
Isolated egress proxy for user URLs¶
Pattern¶
When a service must make HTTP requests to URLs supplied by users — webhook senders, URL preview fetchers, image proxies, URL shorteners, server-side PDF/HTML renderers — route every outbound request through a dedicated egress proxy (typically Envoy) that enforces at send time the same rules the application enforced at submission time:
- Block connections to internal / private IPs.
- Limit traffic to HTTPS ports.
- (Extensible: allow-list specific ports, block specific IP ranges, require specific TLS versions, etc.)
The proxy tier runs in its own Kubernetes service / pod set, physically separated from the rest of the application's outbound traffic. User-URL-touching code paths have no direct network egress — their only path out is through the proxy.
Why — structure forcing DNS-rebinding defence¶
The load-bearing property is that the egress proxy
re-resolves DNS for each outbound request and evaluates
the rules against the actual IP it is about to connect
to. This closes the
DNS-rebinding check-to-send gap that
URL validation alone
leaves open: an attacker's authoritative DNS can flip the
answer between submission-time check and send-time
connect, but at the egress proxy's connect moment, the
DNS answer is re-evaluated and a rebind to 10.0.0.1 is
refused.
URL validation at submission is necessary (UX — tell the user immediately if their URL is invalid; first defence layer against naive misuse). But it is not sufficient for SSRF protection. The egress proxy is the real boundary — canonical verbatim framing from sources/2026-04-21-planetscale-webhook-security-a-hands-on-guide: "No matter how rigorous your URL validations are, you cannot fully trust any URL provided by a user. Because of this, it's critical to isolate and limit where the webhooks service can send HTTP requests."
Why — operational isolation composes with¶
blast-radius containment
Running the user-URL-touching service on isolated Kubernetes machines (the proxy itself + its user-URL worker fleet) means webhook abuse cannot impact other product surfaces. The service can be paused / rate- limited / killed / rolled back independently. See patterns/defense-in-depth-webhook-abuse-mitigation for the full abuse-mitigation stack this composes with.
Why Envoy¶
Natural fit because:
- Cluster-based outbound. Envoy's cluster abstraction lets operators express "these destinations, those rules" without per-request custom code.
- Health checks + circuit breakers. Protect against slow / unresponsive user receivers.
- Metrics + tracing out of the box. Every outbound request observable without application-tier instrumentation.
- xDS dynamic config. Blocklist / allow-list updates can be pushed without process restart.
Alternatives: Squid, HAProxy, NGINX, custom proxies. Envoy is the 2023+ default for greenfield teams already using Kubernetes.
Composition contract¶
- Application-tier validates URL at submission (HTTPS, IP blocklist, domain blocklist, post-DNS re-check) — fast user feedback, first security layer.
- Application-tier enqueues send job into an async queue (Sidekiq in PlanetScale's case).
- Worker picks up job, makes HTTP request through Envoy — no direct egress.
- Envoy re-resolves DNS, evaluates rules against actual connect IP, refuses if private / loopback / blocked port / non-HTTPS.
- Worker receives connection-refused error; records as delivery failure.
Seen in¶
- sources/2026-04-21-planetscale-webhook-security-a-hands-on-guide — Canonical pattern disclosure (2023-11-21, Mike Coutermarsh). PlanetScale deploys webhooks as a dedicated Kubernetes service whose all HTTP egress flows through Envoy. Two enforcement rules at the proxy tier verbatim: "Block any connections to internal/private IPs. Limit traffic to HTTPS ports." The proxy's rules are near-identical to the URL-validation rules deliberately — "It has similar rules as the URL validations above, but are executed when the webhook is being sent." Two enforcement points, one policy. This disclosure also adds a fifth canonical role to Envoy on the wiki (alongside ingress gateway at Databricks, EDS-client-weight at Dropbox, sidecar at AWS App Mesh / ECS Service Connect, JWT-validator at Pinterest) — the outbound-egress-SSRF-guard role.