DEV Community

Davi
Davi

Posted on Originally published at blog.mago.team

Webhook Producers Are SSRF by Default: Seven CVEs the Security Guides Don't Mention

A tenant on your SaaS registers a webhook pointing to http://169.254.169.254/latest/meta-data/iam/security-credentials/. On the next event, your server fires the request. Your AWS role credentials reach their Burp Collaborator. This is not a misconfiguration. It is the default behavior of any webhook producer that does not treat outbound URLs as hostile input.

Every webhook security guide covers HMAC signature verification. None of them cover the producer side. Seven CVEs and bug bounty reports document exploitable SSRF in this class: Strapi, soft-serve, Squidex, MLflow, Gogs, Omise, and Mixmax. The pattern across all of them is the same: accept a user-supplied URL and fire an HTTP request from the application server.

Webhook Registration Is SSRF by Design, Not by Accident

Any webhook producer that accepts user-registered URLs is an SSRF primitive. The only difference between exploitable and safe producers is the presence of network-layer controls at delivery time, not the quality of input validation.

CVE-2024-52588 documented Strapi CMS accepting localhost and 127.0.0.1 as webhook URLs through version 4.25.1. The server made outbound requests without any validation, enabling internal port scanning from the Strapi process. GHSA-vwq2-jx9q-9h9f affected soft-serve: repository administrators could register webhooks targeting internal services with zero URL validation on the registration endpoint.

The Squidex case (GHSA-wxg2-953m-fg2w) removes the distinction between blind SSRF and full-read: the webhook execution log reflects the complete HTTP response body from the internal target. An authenticated attacker sets the URL, triggers an event, reads the response in the log, and extracts IAM credentials or internal service tokens.

The feature is the vulnerability. There is no way to validate a URL used as an HTTP destination without controlling the network layer between registration and delivery.

Validating at Registration and Trusting at Delivery Is Structurally Broken

The TOCTOU pattern in webhook producers: the URL is validated at registration time, but DNS is resolved again at delivery time. What passes validation is not necessarily what receives the request.

CVE-2026-64849 (MLflow, CVSS 9.3) documents this pattern in production, actively exploited in August 2026. The _validate_webhook_url method resolves the URL to a public IP at registration. At delivery, the requests library follows redirects without re-validating the resolved address. The request reaches 169.254.169.254 and the response body is reflected to the unauthenticated caller via POST /api/2.0/mlflow/webhooks/{id}/test.

CVE-2026-47267 (Gogs) is the most instructive: it is a direct bypass of a prior fix. CVE-2022-1285 blocked private-CIDR hostnames at both registration and delivery. CVE-2026-47267 bypassed the delivery check via HTTP redirect after hostname validation passed. Fixing registration validation without controlling delivery behavior delays the next CVE rather than solving the problem.

A One-Line HTTP Server Bypasses Every IP-Range Denylist at Delivery Time

Any validation that inspects the URL string but skips re-inspection after each HTTP redirect is bypassable. A public endpoint returning 302 to an internal IP defeats it. The attacker's server sits in the middle: it receives the request with a valid public IP and redirects to the internal target.

H1:508459 (Omise, $700 bounty, 190 upvotes): the webhook follows an HTTP 303 See Other to an attacker-controlled redirect server. The redirect target is http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-opsworks-ec2-role. The response body contains live IAM credentials. The bypass worked because general redirects were blocked, but HTTP 303 was followed without re-inspection.

H1:243277 (Mixmax): webhook pointed at http://169.254.169.254/latest/meta-data/, triggered simply by sending an email. The confirmed EC2 metadata service response enabled IAM role enumeration. CVE-2026-64849 (MLflow) closes the loop: the /test endpoint reflects the upstream body to an unauthenticated caller, converting a registration-validated URL into full-read SSRF via redirect chain.

DNS Rebinding Defeats IP-Range Blocking Even After the Redirect Gap Is Closed

The redirect bypass closes when the HTTP client stops following redirects to private IPs. DNS rebinding defeats that control without any redirect in the chain.

The attack: the attacker controls a DNS server with a 1-second TTL. Validation resolves attacker.com to 203.0.113.1, a public IP that passes the check. The TTL expires before delivery. The second resolution returns 169.254.169.254. The request reaches the metadata service with no visible redirect. The CVE-2026-64849 (MLflow) advisory documents DNS rebinding as a co-equal vector alongside redirect bypass. They are not separate issues; both paths reach the same outcome.

The MLflow 3.15.0 fix sets the correct standard: a custom transport adapter resolves the hostname once, pins the resolved IP, and verifies that the socket peer address matches the validated IP before the TLS handshake. Any solution that does not pin the resolved address at connection time fails against DNS rebinding.

The Fix Is Network Isolation, Not Smarter URL Parsing

Every URL-parsing denylist has a corresponding bypass. The controls that hold against redirect and DNS rebinding combine connect-time IP verification with network isolation for webhook delivery workers.

Stripe open-sourced Smokescreen: an SSRF-aware HTTP proxy that resolves DNS and enforces IP-range rules at the proxy layer. Stripe and GitHub use this proxy for webhook delivery in production. The architecture closes both the redirect gap and DNS rebinding before traffic reaches application code. The OWASP SSRF Prevention Cheat Sheet positions network-layer controls (firewall egress rules, isolated subnets) as structurally stronger than application-layer URL validation. It explicitly lists webhooks with user-configured URLs as an SSRF vector.

The concrete pattern: webhook delivery workers in a private subnet with egress only to the public internet. Even a compromised worker has no route to the metadata service or internal services. Application-layer URL validation becomes an additional layer, not the sole control.

Auditing Webhook Producers: The Three-Question Test

Identifying a webhook producer vulnerable to SSRF takes 3 questions and a network trace.

Question 1: does the HTTP client receive the URL from user input without passing through an intermediary proxy? If yes, any IP check in application code is bypassable via redirect. Question 2: does delivery resolve the hostname independently of registration-time validation? If yes, DNS rebinding applies. Question 3: does the response body or delivery status reach any caller? If yes, the SSRF is full-read: enumeration becomes credential theft.

The MAGO Intel tool (intel.mago.team) surfaces APIs that accept user-registered URLs and make outbound calls without visible network-layer controls. It identifies webhook endpoints from SaaS producers that match this pattern. The manual complement: register a webhook pointing to a Burp Collaborator or webhook.site and check whether the server's source IP is internal.


Auditing a webhook integration for HMAC bypass is worthwhile. Auditing the producer for SSRF before touching the signature is more worthwhile. If the server makes an outbound request to any URL you register, the signature on that request is irrelevant.

Top comments (0)