All notes
Architecture

Validate the URL your own worker will dial

Any user-supplied URL a server-side worker will later fetch is an SSRF surface. Whet rejects loopback, private, link-local, and cloud-metadata hosts at endpoint-creation time rather than trusting the delivery path to be safe.

Whet lets users register outbound webhook endpoints, and a delivery worker dials those URLs from inside the network. That inside-ness is the whole problem: an unguarded user-supplied host is a server-side request forgery vector, a way to make a trusted component fetch something it should never reach. The fix, landed as a post code-review commit a89e8b1, added an inbound validation guard that rejects loopback, private, link-local, and cloud-metadata hosts at the moment the endpoint is created — not at delivery time. It was flagged as an ADR-candidate, which is the right weight for a decision this load-bearing.

The trust lives in the worker, not the URL

A URL string is inert. It becomes dangerous only when something with network privilege acts on it. The webhook delivery worker runs inside the perimeter, so it can reach 127.0.0.1, RFC1918 ranges, and the 169.254.169.254 metadata endpoint that a user’s browser never could. Registering a URL that points there turns the worker into a proxy for the attacker. The value is untrusted; the actor is trusted; the danger is the composition.

Reject at the write, not at the read

The guard belongs where the untrusted value enters — endpoint creation — rather than where it’s consumed. Validating at delivery time means the dangerous URL already lives in the database, waiting for a future code path to forget the check. Validating at write time means the bad host never persists: there is one gate, at one moment, and every later reader inherits its guarantee for free. The earliest point is also the cheapest one to reason about.

Enumerate the classes, don’t pattern-match strings

The guard rejects by host class — loopback, private, link-local, 169.254 metadata — not by matching suspicious substrings. Blocklists of literals rot; an attacker rotates encodings faster than you patch. Classifying the resolved host against known-dangerous ranges is a closed set that maps to the actual threat. That it shipped quietly alongside a cross-schema join fix and a corrected failed-job count is itself the lesson: the SSRF guard wasn’t a security project, it was a line item in a code-review pass. The surfaces that bite are the ones that look like plumbing.