Can webhooks cause vulnerabilities?
Yes. A webhook endpoint is a public URL that accepts POST bodies from the internet, and a webhook sender fetches URLs its own customers chose. Both directions add attack surface: forged events, replayed deliveries, server-side request forgery, leaked secrets, and payload handling that trusts input it should not.
Forged events on an endpoint that skips verification
The common failure is an endpoint that acts on whatever arrives. Webhook URLs are not secret: they sit in configuration screens, get pasted into support tickets, and show up in proxy logs. Anyone holding one can POST a JSON body that looks exactly like the provider's payment.succeeded event, and a handler that reads the amount and ships the order cannot tell the difference.
The control is a signature. Providers compute an HMAC-SHA256 over the request body with a shared secret and put the result in a header, so a request without a matching webhook signature is rejected before the JSON is parsed. Two details decide whether that check actually holds. Compute the HMAC over the raw bytes that arrived, because middleware that parses and re-serializes JSON changes those bytes and breaks verification. And compare with hmac.compare_digest or crypto.timingSafeEqual rather than ==, since a comparison that returns on the first mismatched byte leaks how much of a guessed signature was correct.
Replay of a delivery that was legitimate
A signature proves who sent a request, not when they sent it. Capture one signed refund event from a log and you can send it again tomorrow: the signature still validates, and a handler that is not idempotent issues another refund.
Providers block this by signing a timestamp alongside the payload, and receivers reject anything outside a window, commonly 300 seconds. The timestamp has to be part of the signed data, otherwise an attacker substitutes a fresh value and keeps the original signature. Deduplicating on the event ID closes the rest, which you need regardless because retries make duplicate deliveries normal.
SSRF when your customers pick the URL
Senders carry a different risk. A system whose job is to POST to arbitrary customer-supplied URLs is an HTTP client that outsiders get to aim. Point an endpoint at http://169.254.169.254/ and the cloud metadata service may answer with credentials. Point it at an internal admin host and your delivery worker reaches something the public internet cannot.
Blocking private ranges by matching the URL string is not enough, because DNS resolves a public-looking hostname to whatever the owner wants, including 127.0.0.1, and can return a different answer between your check and the request. Resolving through a filtering proxy that rejects private and link-local addresses at connection time is the control that holds up. Our SSRF entry covers the attack in more detail.
Secrets and URLs that are themselves credentials
Signing secrets end up in the wrong places: committed to a repository, printed by a debug log, pasted into a chat thread. Whoever holds the secret can forge valid signatures until it is rotated, which is why providers support two active secrets during a rotation window instead of one hard cutover.
Some webhook URLs are the credential. A Slack incoming webhook URL carries no signature at all, so anyone with the string can post to that channel. It belongs in a secrets manager, never in client-side code, and rotating it means deleting the webhook and creating a new one.
Payload handling after the signature checks out
A verified request is authentic, not safe. The payload is still data from another company's system, and its shape changes when they ship. Validate the schema after verification, cap the body size you are willing to buffer, and treat every string as untrusted before it reaches a database query, a shell command, or a template. Endpoints need rate limiting too: verification runs a hash over every request, so a flood of invalid ones is a cheap way to spend your CPU and your logging budget.
Where the fixes live
The list of controls is short and closed, which is the encouraging part. Webhook security 101 works through each one with code, security best practices covers the operational side including logging and secret rotation, and GitHub webhook security shows one provider's scheme end to end. Security is the tradeoff worth weighing against the rest of the disadvantages of webhooks before you commit to them.
Receiving is the easier half: one endpoint, one secret, one checklist. Sending means getting signing, timestamped payloads, secret rotation, and SSRF filtering right for every customer endpoint you deliver to, and getting them right again each time the fleet grows. Svix provides that layer as a service, and Svix Ingest handles verification and ingestion when you are the one taking events in.
Frequently asked questions
Can someone send fake webhooks to my endpoint?
Yes, unless you verify signatures. The URL is all an attacker needs to POST a body that mimics a real event. Verify the HMAC over the raw request bytes with a timing-safe comparison, and reject anything that fails before parsing the JSON.
Do webhook URLs need to be secret?
Treat them as secret, but never rely on secrecy alone. URLs leak through configuration screens, logs, and tickets, so signature verification is what actually protects the endpoint. Slack-style URLs that carry no signature are the exception: there the URL is the only credential, so it belongs in a secrets manager.
Is HTTPS enough to secure a webhook?
No. HTTPS protects the request in transit and is required, but it says nothing about who sent it. An attacker can open a TLS connection to your endpoint just as easily as the real provider can. Authentication comes from the signature, and freshness comes from a signed timestamp.
What is the biggest webhook risk for a company that sends events?
SSRF. Customers supply the destination URLs, so your delivery workers can be aimed at cloud metadata services or internal hosts. Resolve DNS through a proxy that blocks private and link-local addresses at connection time rather than filtering URL strings.