online / endpoints 59 / categories 14 / rate 60/min/ip /

GET /image

GET /image

Image responses where the declared MIME type, magic bytes, embedded dimensions, chunk framing, or format metadata disagree with the actual content. Seven modes across PNG, JPEG, WebP, GIF, and AVIF test how image pipelines handle metadata-vs-bytes mismatches.

mode Which flaw to send. mime-mismatch (default; real PNG bytes served as image/jpeg), magic-byte-lie (PNG signature prefix on a JPEG body), wrong-dimensions (1x1 PNG with IHDR claiming 4000x4000), truncated-png (under-delivered IDAT, no IEND), webp-flag-lie (VP8X flags claim Animation but no ANIM/ANMF chunks follow), gif-lsd-lie (GIF89a LSD claims 100×100 canvas, image frame is 1×1), avif-ftyp-lie (ftyp box brands avif, no meta or mdat boxes follow).

control Compare against the well-formed counterpart: not.catastrophic.io/image side-by-side

build a request:

expect: An image-shaped body whose metadata lies. The specific lie depends on mode. X-Chaos-Image-Note explains the chaos in plain text. Cache-Control: no-transform prevents the CDN edge from re-encoding or sniffing the response.

bash
# Save the body and compare Content-Type to the actual magic bytes.
curl -sD - 'https://chaos.catastrophic.io/image?mode=mime-mismatch' -o /tmp/chaos.bin | grep -i 'content-type\|x-chaos-image'
file /tmp/chaos.bin
import urllib.request
resp = urllib.request.urlopen("https://chaos.catastrophic.io/image?mode=mime-mismatch")
body = resp.read()
print("Content-Type:", resp.headers.get("Content-Type"))
print("X-Chaos-Image-Mode:", resp.headers.get("X-Chaos-Image-Mode"))
print("X-Chaos-Image-Note:", resp.headers.get("X-Chaos-Image-Note"))
print(f"First 16 bytes (magic): {body[:16].hex()}")
# PNG magic: 89504e470d0a1a0a    JPEG magic: ffd8ff
// Type-trusting client: trust Content-Type and pass straight to a decoder.
const res = await fetch("https://chaos.catastrophic.io/image?mode=mime-mismatch");
const bytes = new Uint8Array(await res.arrayBuffer());
const magic = Array.from(bytes.slice(0, 8))
    .map(b => b.toString(16).padStart(2, "0")).join("");
console.log("Content-Type:", res.headers.get("content-type"));
console.log("X-Chaos-Image-Note:", res.headers.get("x-chaos-image-note"));
console.log("First 8 bytes:", magic);
package main

import (
    "encoding/hex"
    "fmt"
    "io"
    "net/http"
)

func main() {
    resp, _ := http.Get("https://chaos.catastrophic.io/image?mode=mime-mismatch")
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))
    fmt.Println("X-Chaos-Image-Note:", resp.Header.Get("X-Chaos-Image-Note"))
    head := body
    if len(head) > 16 { head = head[:16] }
    fmt.Println("First bytes:", hex.EncodeToString(head))
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
fn main() -> Result<(), Box> {
    let resp = reqwest::blocking::get("https://chaos.catastrophic.io/image?mode=mime-mismatch")?;
    println!("Content-Type: {:?}", resp.headers().get("content-type"));
    println!("X-Chaos-Image-Note: {:?}",
        resp.headers().get("x-chaos-image-note"));
    let bytes = resp.bytes()?;
    let head: Vec = bytes.iter().take(16)
        .map(|b| format!("{:02x}", b)).collect();
    println!("First bytes: {}", head.join(""));
    Ok(())
}
// Java 11+ HttpClient.
import java.net.URI;
import java.net.http.*;

public class ImageChaos {
    public static void main(String[] args) throws Exception {
        var client = HttpClient.newHttpClient();
        var req = HttpRequest.newBuilder(URI.create("https://chaos.catastrophic.io/image?mode=mime-mismatch")).build();
        var resp = client.send(req, HttpResponse.BodyHandlers.ofByteArray());
        System.out.println("Content-Type: " +
            resp.headers().firstValue("Content-Type").orElse(""));
        System.out.println("X-Chaos-Image-Note: " +
            resp.headers().firstValue("X-Chaos-Image-Note").orElse(""));
        var sb = new StringBuilder();
        for (int i = 0; i < Math.min(16, resp.body().length); i++) {
            sb.append(String.format("%02x", resp.body()[i]));
        }
        System.out.println("First bytes: " + sb);
    }
}
using var client = new HttpClient();
var resp = await client.GetAsync("https://chaos.catastrophic.io/image?mode=mime-mismatch");
Console.WriteLine($"Content-Type: {resp.Content.Headers.ContentType}");
Console.WriteLine($"X-Chaos-Image-Note: {resp.Headers.GetValues("X-Chaos-Image-Note").FirstOrDefault()}");
var bytes = await resp.Content.ReadAsByteArrayAsync();
Console.WriteLine($"First bytes: {Convert.ToHexString(bytes[..Math.Min(16, bytes.Length)])}");
require "net/http"
uri = URI("https://chaos.catastrophic.io/image?mode=mime-mismatch")
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    res = http.get(uri.request_uri)
    puts "Content-Type: #{res['Content-Type']}"
    puts "X-Chaos-Image-Note: #{res['X-Chaos-Image-Note']}"
    puts "First bytes: #{res.body[0, 16].unpack1('H*')}"
end
# Invoke-WebRequest returns raw bytes in .Content for non-text responses.
$r = Invoke-WebRequest -Uri 'https://chaos.catastrophic.io/image?mode=mime-mismatch'
"Content-Type: $($r.Headers['Content-Type'])"
"X-Chaos-Image-Note: $($r.Headers['X-Chaos-Image-Note'])"
$hex = ($r.Content[0..15] | ForEach-Object { '{0:x2}' -f $_ }) -join ''
"First bytes: $hex"