
Check destinations before sending requests
When an application sends a request to a supplied address, that address needs more than URL validation. Wildo provides shared checks for embedded credentials, reserved hostnames and private or reserved literal addresses.
The webhook delivery path checks at send time and does not follow redirects. This protects stored endpoints as well as newly entered ones; the exact DNS protection depends on the caller’s transport.
Example — Reject an internal-address webhook target
A customer supplies a loopback address as a webhook endpoint. The delivery path refuses it before issuing the request, and the endpoint test uses that same decision.
For engineers
classifyOutboundTargetUrl checks admitted schemes, credentials in the URL, special-use hostnames and literal IP ranges. In the webhook transport the check happens immediately before I/O, not only when the endpoint is saved:
const refusal = refuseUnsafeWebhookTarget(params.url);
if (refusal) {
return { networkError: refusal, durationMs: Date.now() - startedAt };
}
const abort = new AbortController();
const timer = setTimeout(() => abort.abort(), REQUEST_TIMEOUT_MS);
This selected fragment comes from m2m-webhook-signed-request.backend.utils.ts. A refusal is returned as a transport result; the worker and probe then report it according to their own outcome contracts. The same transport uses redirect: 'manual', so a redirect cannot silently move delivery to a different address.
Distinguish the protection levels
| Mechanism | What it checks |
|---|---|
| URL classifier | Scheme, embedded credentials, literal addresses and special-use names |
| DNS-resolving check | Addresses returned for a hostname before connection |
| Pinned outbound fetch | Address classification inside the connection lookup path |
These are not interchangeable. The webhook path currently uses the URL classifier and ordinary fetch; an ordinary hostname resolving to a private address is outside that classifier’s protection. A preflight DNS check alone also leaves a change-between-check-and-connect problem. The client-metadata fetcher uses pinnedOutboundFetch to close that gap on its own path.
Do not claim that every outbound request in the framework has identical protection. When implementing a new server-side callback or metadata reader, use the transport suitable for its trust boundary and permitted schemes, and preserve redirect and timeout handling. Network egress policy remains a deployment responsibility.
The classifier does not establish reachability or endpoint ownership. It answers whether the supplied target is disallowed by its checks. Use the endpoint probe to investigate a webhook’s response, without interpreting acceptance as a general network-safety audit.