GET /svg
Returns SVG documents that misbehave for browser renderers, image processors, and XML-strict parsers. SVG is an XML+rendering hybrid so chaos modes span both worlds: malformed XML structure, external-resource references, recursive <use> chains, and non-conformant namespaces.
mode
mismatched-tags (default; `<g>` closes before its child `<rect>` — XML parsers reject, lenient renderers recover), external-image-ref (`<image href="http://nonexistent.invalid/...">`; processors that resolve external refs hang), circular-use (`<use>` chain references itself; non-conformant renderers may recurse), bad-namespace (xmlns declares a non-SVG namespace; namespace-aware processors refuse to render).
control Compare against the well-formed counterpart: not.catastrophic.io/svg side-by-side
build a request:
expect: 200 OK with Content-Type: image/svg+xml; charset=utf-8. Cache-Control: no-transform prevents the CDN edge from rewriting the body. X-Chaos-Svg-Mode reflects the selected mode; X-Chaos-Svg-Note explains the flaw.
curl -i 'https://chaos.catastrophic.io/svg?mode=mismatched-tags'
# SVG is XML; parse with defusedxml for safety on untrusted input.
# cairosvg and other rasterisers behave differently on each mode —
# external-image-ref typically hangs while fetching, circular-use
# may OOM, bad-namespace yields a blank raster.
import urllib.request
from defusedxml import ElementTree as DET
raw = urllib.request.urlopen("https://chaos.catastrophic.io/svg?mode=mismatched-tags").read()
try:
root = DET.fromstring(raw)
print(f"Root tag: {root.tag}")
except Exception as e:
print(f"Parse error: {type(e).__name__}: {e}")
// Browsers tolerate a lot of malformed SVG when used as
;
// serving the same bytes to DOMParser as image/svg+xml is stricter.
const res = await fetch("https://chaos.catastrophic.io/svg?mode=mismatched-tags");
const raw = await res.text();
console.log("Mode:", res.headers.get("X-Chaos-Svg-Mode"));
const doc = new DOMParser().parseFromString(raw, "image/svg+xml");
const err = doc.querySelector("parsererror");
console.log("Parsed clean:", !err);
if (err) console.log("Parser said:", err.textContent);
package main
import (
"encoding/xml"
"fmt"
"io"
"net/http"
"strings"
)
func main() {
resp, _ := http.Get("https://chaos.catastrophic.io/svg?mode=mismatched-tags")
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
fmt.Println("Mode:", resp.Header.Get("X-Chaos-Svg-Mode"))
// SVG is XML; encoding/xml refuses DOCTYPE entirely so the
// billion-laughs-style modes never reach element parsing.
var v any
dec := xml.NewDecoder(strings.NewReader(string(raw)))
err := dec.Decode(&v)
fmt.Println("Parse error:", err)
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
// resvg = "0.43" (or usvg = "0.43" for parse-only)
use usvg::{Options, Tree};
fn main() -> Result<(), Box> {
let raw = reqwest::blocking::get("https://chaos.catastrophic.io/svg?mode=mismatched-tags")?.bytes()?;
match Tree::from_data(&raw, &Options::default()) {
Ok(tree) => println!("Parsed: {}x{}", tree.size().width(), tree.size().height()),
Err(e) => eprintln!("Refused: {e}"),
}
Ok(())
}
// Requires Apache Batik (org.apache.xmlgraphics:batik-transcoder).
// Batik resolves external references by default; toggle via the
// ALLOW_EXTERNAL_RESOURCES_KEY transcoding hint when handling
// untrusted SVG.
import org.apache.batik.transcoder.*;
import org.apache.batik.transcoder.image.PNGTranscoder;
import java.net.URI;
import java.net.http.*;
import java.io.*;
public class SvgChaos {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(URI.create("https://chaos.catastrophic.io/svg?mode=mismatched-tags")).build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofInputStream());
try {
var t = new PNGTranscoder();
t.transcode(new TranscoderInput(resp.body()), new TranscoderOutput(OutputStream.nullOutputStream()));
System.out.println("Rasterised clean");
} catch (Exception e) {
System.err.println("Refused: " + e.getMessage());
}
}
}
// Svg.NET library; parsing only (no raster).
using Svg;
using var client = new HttpClient();
var raw = await client.GetStreamAsync("https://chaos.catastrophic.io/svg?mode=mismatched-tags");
try {
var doc = SvgDocument.Open(raw);
Console.WriteLine($"Parsed: {doc.Width}x{doc.Height}");
} catch (Exception e) {
Console.Error.WriteLine($"Refused: {e.Message}");
}
# Nokogiri can parse SVG as XML; for raster use rsvg / librsvg
# bindings if you need to test rendering behaviour.
require "net/http"
require "nokogiri"
resp = Net::HTTP.get_response(URI("https://chaos.catastrophic.io/svg?mode=mismatched-tags"))
raw = resp.body
puts "Mode: #{resp['X-Chaos-Svg-Mode']}"
doc = Nokogiri::XML(raw) { |c| c.strict.nonet }
puts "Errors: #{doc.errors}"
puts "Root: #{doc.root && doc.root.name}"
# PowerShell has no built-in SVG renderer; parse as XML and inspect
# the structure. For actual rasterisation, shell out to Inkscape or
# rsvg-convert if installed.
$resp = Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/svg?mode=mismatched-tags' -SkipHttpErrorCheck
$resp.Headers['X-Chaos-Svg-Mode']
try {
[xml]$svg = $resp.Content
"Root: $($svg.DocumentElement.LocalName) (namespace: $($svg.DocumentElement.NamespaceURI))"
} catch {
"Refused: $($_.Exception.Message)"
}
headers
body