DEV Community

Cover image for Most webhook security guides protect the wrong side. The scary part is delivery.
Aditya Agarwal
Aditya Agarwal

Posted on

Most webhook security guides protect the wrong side. The scary part is delivery.

Everyone secures webhook ingestion. Almost nobody talks about SSRF via the delivery worker.

I've been staring at webhook architectures for years, and the security conversation is almost always backwards. We obsess over verifying inbound payloads while leaving the outbound side wide open.

Why Your HMAC Doesn't Save You Here

HMAC verification only protects ingestion, not outbound delivery to tenant URLs. That signature proves the payload came from who it claims. Great.

But your delivery worker — the thing that POSTs events to customer-provided URLs — has a completely different threat model. HMAC doesn't even enter the picture on that side.

Think about it. A tenant registers https://totally-legit-domain.com/webhook as their endpoint. You validate the URL looks fine. You maybe even check it doesn't resolve to a private IP. Then you move on with your life.

DNS Rebinding: The Actual Scary Part

Here's where it gets ugly. DNS rebinding can redirect webhook deliveries to internal IPs like 169.254.169.254.

The attack works like this:

→ Tenant registers a domain they control
→ At registration time, it resolves to a perfectly normal public IP
→ Your validation passes
→ Later, the DNS record flips to 169.254.169.254 (the cloud metadata endpoint)
→ Your delivery worker happily POSTs to it, potentially leaking cloud credentials

Your worker just became a proxy into your own infrastructure. The tenant didn't hack anything. They just gave you a URL and waited. 🎯

This isn't theoretical. Cloud metadata endpoints are the crown jewels. One leaked IAM credential from that 169.254 address and it's game over.

Validate at Delivery Time, Every Time

Private IP blocklists must be checked at delivery time, not just registration time. I can't stress this enough.

Checking the URL once when the tenant sets it up is not sufficient. DNS records change. That's literally what DNS rebinding exploits.

Every single outbound request from your delivery worker needs to:

→ Resolve the hostname fresh
→ Check the resolved IP against a private range blocklist before opening the connection
→ Reject anything pointing to 10.x, 172.16-31.x, 192.168.x, 169.254.x, or localhost

Some HTTP libraries will follow redirects automatically too. A 302 hop to an internal IP is just as dangerous. You need to validate at every step of the chain, not just the initial resolution.

This Is an Architecture Problem, Not a Config Problem

The frustrating part is that most webhook guides treat security as "add HMAC and you're done." That's security theater for the delivery path. 🔒

If you're building a webhook system, the delivery worker is the most dangerous component you own. It makes outbound HTTP requests to attacker-controlled URLs. Read that sentence again.

You're essentially running an HTTP client that takes instructions from your tenants. That deserves the same paranoia you'd give to user-uploaded code execution.

At a high level, the decisions that actually matter:

→ Pin DNS resolution to the moment of delivery and validate the IP
→ Disable HTTP redirects or re-validate after each hop
→ Run delivery workers in a network segment with no access to internal services or metadata endpoints
→ Treat every tenant URL as hostile, every time, forever

The Takeaway

Your inbound webhook security is probably fine. Your outbound delivery worker is probably a loaded footgun pointed at your cloud metadata endpoint. The fix isn't complicated — validate DNS resolution at delivery time, block private IPs, isolate the worker network. But you have to actually do it, and most teams don't because every tutorial stops at HMAC. 😅

What does your webhook delivery pipeline look like — are you validating resolved IPs on every outbound request, or just at registration time?

Top comments (0)