Published on

SVIXSEC-2026-0001: Svix SSRF bypass

Authors
  • avatar
    Name
    James Brown
    Twitter

Cover image

Svix is the enterprise ready webhooks sending service. With Svix, you can build a secure, reliable, and scalable webhook platform in minutes. Looking to send webhooks? Give it a try!

At Svix, we take our customers' security very seriously, and that includes providing full and detailed explanations when something goes wrong. This incident is the first notable security incident at Svix; this post will describe what happened, what we've done to fix it, and how it affects our customers.

This issue is still pending CVE assignment, but Svix has reserved CAN-2026-2033646 as a temporary identifier and we're using SVIXSEC-2026-0001 as an internal identifier. This document will be updated when a formal CVE number is assigned.

We'd like to thank external security researcher Kim Dong-Uk for reporting this. If you would like to report a security concern to Svix, you can always contact us at responsible.disclosure@svix.com, as spelled out in our security.txt file.

The Svix server, at its heart, is a router to send data from our direct customers to HTTP1 endpoints provided by our customers' customers. One of the things that Svix gives you is robust protection against Server-Side Request Forgery (SSRF). This vulnerability is a way for an attacker to bypass those SSRF protections in some scenarios and when targeting nodes by IP address. Before we can explain this vulnerability in detail, we need to understand what SSRF is and why it's dangerous.

Server-Side Request Forgery allows an attacker to emit network traffic (e.g., an HTTP request) from your network, targeted at an arbitrary destination.

Why is this bad? Imagine that you're a SaaS business deploying your infrastructure in production. A typical tiered architecture might include multiple different network segments: one for databases, one for in-house-developed applications, and one representing the "Internet", with firewalls between them to manage access.

Traditional tiered architecture

This is common in Cloud environments, where you might have a single VPC with several different subnets in it, and with "internal" services like databases living exclusively on private IPs, unreachable by the world at large.

In the 90's, this would have been the extent of your security precautions; in 2026, after decades of surveillance and malicious actors, most modern systems support authentication2 and network-level traffic protection with protocols like IPsec or TLS. However, companies may be at different stages in joining the Zero Trust Architecture revolution, and it's not uncommon to still have some endpoints that exclusively rely on network segmentation for security. An SSRF bypass allows an attacker who knows where those vulnerable endpoints are to reach them from the outside world.

If, for example, a business were running both the Svix server and an internal unauthenticated WebDAV server in the same network space, an attacker who knew (or could guess) the file-server's IP address (say, 10.1.2.3) could craft an endpoint with a URL like https://[::ffff:0a01:0203]/some/malicious/path and end up creating a file on that server. This relies on the target's IP address being known or guessable, the target not having any authentication in place, and the target having valid TLS certificate (since Svix, by default, disallows sending webhooks to unencrypted http:// endpoints).

For more information about SSRF, see our earlier blog post.

Technical Details

In the Svix server, we protect from SSRF vulnerabilities by filtering outbound connections in the application. Our backend uses hyper to make outbound connections and we secure into it in two ways:

  • Providing a custom DNS resolver which filters out any blocked IPs and also protects from rebinding attacks
  • Detecting when the URL will not use DNS because it contains an IP literal, and applying filtering directly
  • Disregarding redirects

Our cloud environment is a bit more sophisticated, and has additional network controls in place around the workers that send outbound requests.

SVIXSEC-2026-0001 is a bug in the second of these; URLs which contained an IPv6 address literal3 enclosed in square brackets were not detected. This means that an attacker who had permission to create new Endpoints could create one that would point at an arbitrary IP address; either an IPv6 address like 2001:db8::cafe:d00d or an IPv4-mapped IPv6 address like ::ffff:c0a8:00014. They could then cause your webhooks to be delivered there, which might have unexpected effects depending on what resides at that address

The root cause of this most likely lies in Svix's roots migrating from Python to Rust; in Python, a call like urllib.parse.urlparse("https://[1.2.3.4]").hostname yields the string "1.2.3.4"; however, in both url and http::uri, the equivalent call "[1.2.3.4]".parse::<url::Url>().unwrap().host() returns "[1.2.3.4]".

This was mitigated by detecting if the returned host value is wrapped in square brackets and trimming them; at that point, our existing IP filtering logic can take over.

Future planned improvements include more-directly overriding the network layer in hyper. Unfortunately, while other programming languages offer a consistent interface for overriding net work I/O (go's is called Dial), Rust's ecosystem isn't quite so straightforward, and we're working on the most maintainable way to implement it.

Legibility

This is the first CVE filed against Svix, and as part of the process we wanted to make our code more legible to security scanners and production security engineering teams. We've done this by making two changes to all of our containers:

  • We now set OCI annotations on all of our Docker images, allowing you to see the version through docker inspect even if the tag isn't available
  • Binaries built on Linux (including those running in Docker) now have UAPI.8 Package Metadata embedded in them, including the (extension) appCpe field. This allows security scanners like syft to detect the specific version of the binary on disk; scanners will now report CPEs like cpe:2.3:a:svix:svix-server:1.98.0:*:*:*:*:*:*:*. This is being done using a linker script emitted from rust-executable-metadata, a small library we've open-sourced.

In addition to the Svix server, these changes have been rolled out for the Svix CLI, Svix Bridge, and Diom.

We hope that that will make it easier for users to inventory their Svix applications going forward.

Applying for a CVE in 2026

Svix is not a CNA, so in order to obtain this CVE, we had to work with an existing CNA; we choose to use MITRE, as the long-standing industry standard. Here's a glimpse at the MITRE CVE ID request form:

MITRE CVE ID Request Form

If ever there was an example of a UI designed by engineers!

We have filed a request to be assigned a CVE and are still pending a response from MITRE.


If you have any questions or concerns, please don't hesitate to reach out to support@svix.com.

Stay tuned at https://www.svix.com/blog for future posts, follow us on Github, Mastodon, or RSS for the latest updates for the Svix webhook service, or join the discussion on our community Slack.

Are you interested in building build reliable, secure, data-driven applications for server-to-server communication? Come work with us!

Footnotes

  1. Well, mostly HTTP

  2. Sometimes just a username and password, but, particularly in cloud environments, authentication often involves hard-to-forge machine identities

  3. Note that the RFC 3986 § 3.2.2 allows any IP literal in square brackets; this is permitted by the Rust http::uri library but not the url library, which only allows IPv6 literals

  4. This corresponds to 192.168.0.1