Webhook Security: Signing, Verification and SSRF Risks
Webhooks connect your product to payment providers, code hosts and customer systems. They also open two security risks: accepting forged webhooks, and, if you send webhooks to customer URLs, being used as a proxy into internal networks.
Receiving webhooks safely
Your webhook endpoint is public. Anyone can send it a request that looks like "payment succeeded." Without verification, attackers can mark orders as paid, trigger provisioning or corrupt data.
Verify signatures
Most providers sign each webhook with a shared secret, using an HMAC over the raw body and a timestamp. Verify it before doing anything:
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const [t, sig] = parseSignatureHeader(header);
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
return ok && fresh;
}
Key points:
- Use the raw request body, not a re-serialised JSON object, or signatures will not match.
- Compare in constant time with a timing-safe function.
- Check the timestamp to reject old, replayed messages.
- Use the provider's official library where available.
Prevent replays and duplicates
Providers retry deliveries, and attackers may replay captured messages. Store event IDs and ignore duplicates. Make handlers idempotent.
Do not trust the payload blindly
For critical events, fetch the object from the provider's API to confirm its state, rather than trusting the webhook body alone.
Respond quickly
Acknowledge within a few seconds and process asynchronously, so slow handlers do not trigger retries and duplicate processing.
Sending webhooks safely
If your product lets customers configure webhook URLs, your servers make requests to arbitrary destinations. That is a server-side request forgery risk.
Protect against it:
- Resolve the destination and block private, loopback, link-local and metadata IP ranges, then connect to the validated IP to prevent DNS rebinding.
- Do not follow redirects, or re-validate each hop.
- Send from an isolated network with no access to internal services.
- Limit response size and time, and do not show full responses to users.
- Sign outgoing webhooks so your customers can verify them.
Webhook security checklist
| Receiving | Sending |
|---|---|
| Verify HMAC signatures on the raw body | Block internal and metadata IPs |
| Check timestamps for freshness | Prevent DNS rebinding |
| Deduplicate by event ID | Disable or validate redirects |
| Confirm critical state via API | Isolate the sending service |
| Keep secrets in a secrets manager | Sign outgoing payloads |
Testing webhooks
SecurityInfinity tests webhook receivers for missing signature validation and replay, and tests webhook configuration features for SSRF. Start free.
Frequently asked questions
Is IP allowlisting enough to verify webhooks?
It helps, but provider IP ranges change and may be shared. Signature verification is the reliable control.
Should webhook endpoints require authentication?
They cannot use normal user authentication. Signatures act as the authentication mechanism.
What if a provider does not sign webhooks?
Use a secret token in the URL path as a minimum, confirm event state through the provider's API, and push for signing support.