heygrc
Answer

How do I fetch a user-supplied URL or webhook without SSRF?

Validate the target before you fetch it: require https, resolve the host, and reject private, internal, and link-local addresses (including cloud metadata endpoints). Prefer an allowlist where the destinations are known, and do not follow redirects blindly. Server-side request forgery is an input-validation problem (NIST 800-53 SI-10), and the check lives in the code that makes the request.

  1. Validate the target

    Only allow the schemes you intend (usually https), and reject addresses in private, loopback, link-local, and metadata ranges. Validate the resolved address at connection time, not just the URL up front, since DNS can resolve differently between a preflight check and the actual request (DNS rebinding).

  2. Prefer an allowlist

    If the set of destinations is known (a fixed list of partner endpoints), allowlist them rather than accepting arbitrary URLs. The narrower the input you accept, the less there is to get wrong.

  3. Do not follow redirects blindly

    A redirect can send a validated public URL to an internal address on the next hop. Re-validate on each redirect, or disable following redirects for user-supplied targets.

webhooks/send.ts+2 -1
async function send(url, payload) {-  return fetch(url, { method: 'POST', body: payload })+  // safeFetch validates the RESOLVED address at connection time+  return safeFetch(url, { method: 'POST', body: payload, allowRedirects: false })}
heygrcNIST 800-53 SI-10

Validating the resolved address at connection time, not just the URL up front (which DNS rebinding can defeat), stops a crafted target from reaching internal services.