Safeguard
Developer Tools•

How do you send webhooks securely as the provider?

A provider-side checklist for outbound webhooks: signed headers, per-endpoint secrets, timeouts, retries, SSRF controls and rotation without downtime.

Safeguard Security Team
4 min read

To send webhooks securely, sign every delivery with a per-endpoint secret, include a unique id and a timestamp in the signed content, route requests through an egress path that cannot reach internal services, set a timeout, retry with backoff, and disable endpoints that stay broken.

Definition

An outbound webhook is an HTTP request your system makes to a URL a customer gave you. Most webhook advice targets the receiver. This is the sender's view, where your servers make requests to addresses you do not control, so you carry the risk of both forged deliveries and server-side request forgery.

The open Standard Webhooks specification, version 1.0.0, gives a concrete baseline. It is a community specification, not a law, so use it as a reference point.

The signed message

Standard Webhooks defines three headers: webhook-id, a unique identifier that stays the same across retries; webhook-timestamp, an integer Unix timestamp in seconds; and webhook-signature, a space-delimited list of signatures. The ID, timestamp and body are joined with full stops and signed. The spec says the ID and timestamp must not be user controllable, or at least must not contain a full stop.

Receivers should check the timestamp is within a tolerance of the current time to prevent replay. The spec does not fix a window, so choose one and document it. See how to verify a webhook signature.

Checklist

AreaWhat to do
SecretsRandom, per endpoint. The spec suggests 24 to 64 bytes, base64 encoded, with a whsec_ prefix for symmetric keys
RotationSign with both old and new keys for a period, put both signatures in the header, receivers accept any match
TimeoutThe spec suggests roughly 15 to 30 seconds
Payload sizeUsually under 20 KB; link to large assets instead
RetriesBackoff with random jitter, over multiple days, using the same webhook-id each time
SuccessTreat any 2xx as success and anything else as failure
SSRFSend through a filtering proxy that blocks internal IP ranges, with workers in a subnet that cannot reach internal services
Source IPsSome customers want a fixed list, so publish one if you can

Steps

  1. Give each customer endpoint its own secret and show it once at creation.
  2. Build the signing function once and test it with fixed vectors.
  3. Put webhook delivery workers behind an egress filter and block private, loopback and link-local ranges.
  4. Resolve and validate the destination at send time, not only when it was saved. See SSRF allow lists versus deny lists for webhooks.
  5. Add delivery logs customers can see, with the response code and a short body excerpt.
  6. Provide a replay button so receivers can recover from outages.

Why egress control matters

Anyone who can register a URL can try to point it at an internal address. The risk is yours, since your servers make the request. Network level controls hold even if a code check is missed.

Where Safeguard fits

Safeguard's API security scanning and policy gates help you check outbound request handling and catch risky dependency versions before release. The free scan is at https://gold.safeguard.sh/scan.

Try it yourself

Click through it at your own pace, or open it full screen.

Quick check

Should every customer share one signing secret?

No. Use a secret per endpoint so one leak does not affect others, and so you can rotate independently.

Should the webhook id change on a retry?

No. Keep it the same so receivers can detect duplicates.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.