← All cybersecurity posts

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:

  1. Resolve the destination and block private, loopback, link-local and metadata IP ranges, then connect to the validated IP to prevent DNS rebinding.
  2. Do not follow redirects, or re-validate each hop.
  3. Send from an isolated network with no access to internal services.
  4. Limit response size and time, and do not show full responses to users.
  5. Sign outgoing webhooks so your customers can verify them.

Webhook security checklist

ReceivingSending
Verify HMAC signatures on the raw bodyBlock internal and metadata IPs
Check timestamps for freshnessPrevent DNS rebinding
Deduplicate by event IDDisable or validate redirects
Confirm critical state via APIIsolate the sending service
Keep secrets in a secrets managerSign 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.

Find what attackers can see, before they do.

AI pentesting agents test your web app, API and cloud, and every finding comes with evidence and a fix. First report in about 10 minutes.

Stay ahead of attackers.

New vulnerabilities, breach write-ups and practical fixes. A few emails a month.