Introduction
Webhooks are the glue of modern SaaS architectures. Stripe sends payment events, GitHub triggers CI/CD pipelines, and Slack delivers message notifications — all through HTTP callbacks. But this convenience creates a sprawling attack surface that most organizations completely overlook.
The Webhook Trust Problem
When you configure a webhook, you're essentially telling a third party: "Send HTTP requests to this URL, and I'll trust and process whatever you send." This creates several fundamental security challenges.
Attack Vector 1: Unsigned Payloads
Many webhook implementations skip signature verification entirely:
// VULNERABLE: No signature verification
app.post('/webhooks/payment', async (req, res) => {
const event = req.body;
if (event.type === 'payment.completed') {
await fulfillOrder(event.data.order_id); // Trusts unverified data
}
res.sendStatus(200);
});
An attacker who discovers this endpoint can forge events:
curl -X POST https://target.com/webhooks/payment \
-H "Content-Type: application/json" \
-d '{"type":"payment.completed","data":{"order_id":"ORD-9999","amount":0}}'
Result: Order fulfilled without payment.
Attack Vector 2: Replay Attacks
Even with signature verification, webhooks are vulnerable to replay attacks if they don't track processed event IDs:
1. Legitimate webhook fires: payment.completed (amount: $100)
2. Attacker intercepts the signed payload
3. Attacker replays the exact same signed request 100 times
4. Application processes 100 fulfillments for 1 payment
Attack Vector 3: SSRF via Webhook URLs
Applications that allow users to configure webhook URLs are vulnerable to SSRF:
POST /api/settings/webhooks
{
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
"events": ["user.created"]
}
When the event fires, the application makes a request to the cloud metadata service and may log or return the response.
Attack Vector 4: Information Disclosure in Logs
Webhook payloads often contain sensitive data — customer emails, payment details, internal IDs. If these payloads are logged (and they usually are), they create a secondary data store that bypasses access controls.
Attack Vector 5: Race Conditions
Webhooks are asynchronous by nature. When multiple webhooks fire simultaneously for related events, race conditions can occur:
T1: webhook: subscription.cancelled → begin cancellation process
T2: webhook: invoice.paid → provision resources for "active" subscription
T3: cancellation completes → user has free resources
Our Assessment Approach
1. Endpoint Discovery
We enumerate webhook endpoints through documentation, JavaScript source analysis, and brute-force common paths (/webhooks, /hooks, /callbacks, /api/events).
2. Signature Bypass Testing
We test for missing, weak, or improperly implemented signature verification — including timing attacks against HMAC comparison.
3. Replay Testing
We capture legitimate webhook payloads and replay them to test for idempotency enforcement.
4. Payload Manipulation
Even with valid signatures, we test whether the application validates the semantic content of payloads — can we modify amounts, user IDs, or event types within the signed envelope?
5. Webhook URL Injection
For applications that accept user-configured webhook URLs, we test for SSRF, open redirect chains, and DNS rebinding.
Remediation Framework
- Always verify signatures using the provider's recommended method (HMAC-SHA256, RSA, etc.)
- Implement idempotency by tracking processed event IDs with a TTL
- Validate payload content against your own records — don't trust amounts, statuses, or IDs from webhooks alone
- Set timeout and size limits on webhook processing to prevent resource exhaustion
- Validate webhook URLs by resolving DNS, blocking internal ranges, and requiring HTTPS
- Encrypt webhook payloads at rest if you log or store them
- Use webhook secrets rotation and support multiple active secrets during rotation periods
Conclusion
Webhooks are trusted entry points into your application that bypass your frontend, authentication layer, and often your API gateway. Every webhook endpoint deserves the same security scrutiny as a public-facing API — because that's exactly what it is. In our experience, webhook-related vulnerabilities are present in over 60% of the applications we assess, and they're almost never caught by automated scanning.