---
title: 'JSON Schema References Considered Harmful'
authors: ['jbrown']
date: 2026-11-12T12:00:00
tags: ['technical', 'rust', 'security']
summary: 'Walking through a security issue caused by a surprising behavior in JSON Schema validation'
---

Svix recently found and remediated a frustrating vulnerability in one of our endpoints, introduced due to a combination
of a bad specification and risky defaults in an open-source library. This blog post walks through the
details and what we as a community of engineers can do to _stop_ having the same family of problem every
few years.

## Background

["JSON Schema"](https://json-schema.org/) is a meta-language for writing <abbr title="the plural of schema">schemata</abbr> of other file formats; basically, a language for describing
formats. JSON Schema documents are themselves valid JSON[^meta], and expected to be applied to JSON-like data[^json-like].
In addition to normal schema constructs (primitive types like `number` and `string`, and composite types like `object` and `array`)
JSON Schema includes facilities for decomposing schemata into multiple different sections or files, which can be referenced
using the [`$ref` keyword](https://json-schema.org/draft-07/draft-handrews-json-schema-01#rfc.section.8.3). These can either be other fragments of the same document
(written as `#/path/to/other/section`), or entirely-other JSON Schema files hosted at an arbitrary URI.

Svix allows users to upload arbitrary schemata for Event Types (as part of [v1.event-type.create](https://api.svix.com/docs#tag/Event-Type/operation/v1.event-type.create))
and uses the open-source Rust [jsonschema](https://crates.io/crates/jsonschema) library to validate those schemata.
This library automatically (and, as of v0.21.0, _eagerly_) handles
dereferencing `$ref` entries, including fetching arbitrary HTTP Resources and loading files off of disk if a `file:///` URI is specified. If a resource doesn't
include a valid JSON Schema document, the error message will include fragments of the affected document.

If this problem is starting to sound a lot like the [external entity expansion][XXE] attacks that have plagued XML since 1998, well, you're not wrong.
There's nothing new under the sun, and as long as the same enterprise architecture astronauts keep building the same kinds of systems the same ways, we'll have the same security problems.
Large applications inevitably develop a huge API surface area[^agents], and every <abbr title="Interface Description Language">IDL</abbr> inevitably ends up grappling with the
same problems of how to foster type-reuse and DRY principles in schema design. XML did it, Avro did it, and now here we are with the same problem in JSON Schema.

## Svix Impact

An attacker could use this as a primitive to make arbitrary HTTP GET requests to any URI from the (potentially-network-privileged) standpoint of the Svix server.
If these GET requests returned valid JSON that was not a valid JSON Schema document, the error message may contain fragments of the returned document[^arbitrary-read].
There do not appear to have been any such malicious schemata uploaded to the Svix cloud environment.
Any attacker would have to already have organization-level access to any OSS or Enterprise deployment, so this is an unlikely attack vector there.
Nonetheless, OSS customers are encouraged to upgrade to v1.104.0 and Enterprise customers are encouraged to upgrade to v1.3116.0 or later.

## Looking to the Future

We look forward to an eventual future where Rust offers tools for robustly consuming third-party libraries without having to painstakingly audit their code;
some kind of comprehensive entitlements system like [Joe-E](https://www.ndss-symposium.org/wp-content/uploads/2017/09/met.pdf), but for Rust. Barring language features,
a carefully-designed microservice architecture, or a decomposition into communicating [wasm](https://rust-lang.org/what/wasm/) [components][WASI] could be an effective strategy to reduce
dependency risk.

This is also a good opportunity to restate a principle for library development: delegate I/O to your callers. The choice that `jsonschema` embeds its own HTTP client by default
is more than a little maddening -- aside from the security issues, it also makes testing quite a bear. Dependency Injection can be a valuable pattern for this sort of thing;
if `jsonschema` took a mandatory [`Retrieve`](https://docs.rs/jsonschema/latest/jsonschema/trait.Retrieve.html) instead of shipping a "convenient" pre-baked option, this
issue could never have arisen.

Alas, you have to go to war with the army you have, so for now it's just important for software engineers to be vigilant about the third-party libraries that we use and depend on &mdash; a cursory examination of JSON Schema wouldn't make most engineers perk up about XXE risks and arbitrary network requests.
Every dependency needs to be fully understood by the humans responsible for integrating and maintaining it.

---

If you have any questions or concerns, please don't hesitate to reach out to [support@svix.com](mailto:support@svix.com).

Stay tuned at [https://www.svix.com/blog](https://www.svix.com/blog) for future
posts, follow us on [GitHub](https://github.com/svix), [Mastodon](https://mastodon.social/@svixhq), or [RSS](https://www.svix.com/blog/rss/) for
the latest updates for the [Svix webhook service](https://www.svix.com), or
join the discussion on [our community Slack](https://www.svix.com/slack/).

Are you interested in working with us to build and secure cool Rust applications for server-to-server communication?
[Come work at Svix!](https://www.svix.com/careers/)

[XXE]: https://community.owasp.org/vulnerabilities/XML_External_Entity_(XXE)_Processing
[WASI]: https://component-model.bytecodealliance.org/

[^meta]: Yes, of course there's a [JSON Schema schema for JSON Schema](https://json-schema.org/draft/2020-12/schema). Unfortunately, it is not referred to as the meta-circular schema...

[^json-like]: For example, JSON Schema is used to describe the schemata for Kubernetes, even though Kubernetes configurations are usually written in YAML instead of JSON

[^agents]: A problem which LLM-assisted software development, which makes new code cheap and good taste expensive, is unlikely to ameliorate

[^arbitrary-read]: An attacker could also trigger arbitrary file reads and, if those files contained valid JSON that was not a valid JSON Schema document, read fragments of those files. There aren't any interesting JSON files on any of the Svix containers, though.
