ADR 0003: Security model
- Status: accepted
- Date: 2026-09-26
Context
Section titled “Context”An image proxy fetches attacker-chosen URLs and decodes attacker-supplied bytes with C libraries. Classic failures: SSRF into cloud metadata or internal services, open proxying/abuse, decompression bombs, malicious SVG (XSS, XXE, external fetches), and decoder memory-safety bugs.
Decision
Section titled “Decision”- Allowlist is mandatory. Configured sources are the allowlist. With no sources and no
XI_DEV_MODE=true, the server refuses to start. - SSRF defence at connect time: dialer
Controlhook validates the actual peer IP (defeats DNS rebinding) against deny lists (loopback, RFC 1918, link-local incl. metadata IPs, CGNAT, ULA, multicast, IPv4-mapped/NAT64 variants), port allowlist, per-hop redirect re-validation, no HTTPS→HTTP downgrade, max redirects. Private networks require explicit opt-in. - Signing: imgproxy-compatible HMAC-SHA256 with key/salt pairs (multiple for rotation) plus each dialect’s native scheme (imgix MD5
s, thumbor HMAC-SHA1, Cloudinarys--…--, ImageKitik-s, Bunny token). Constant-time comparison. Unsigned requests governed byallow | restricted | deny;restrictedlimits sizes/qualities for client-generated URLs. - Encrypted sources: AES-CBC with PKCS#7 and IV prefix, URL-safe base64, imgproxy-compatible.
- Resource limits enforced before decode: source bytes, pixels (header probe), frames, frame pixels, PDF pages, RAW demosaic pixels, result dimensions; request/download timeouts; queue timeouts; libvips work cancelled via kill flag.
- Decoder hardening:
vips_block_untrusted_set(TRUE)then re-enable only shipped loaders;fail_on=warning; ImageMagick restricted to PSD/PSB bypolicy.xmlwith resource caps; own BMP/ICO decoders fuzzed; SVG sanitised in Go before librsvg or passthrough; SVG responses get a sandboxing CSP. - Container: non-root UID 65532, read-only root filesystem compatible, no shell tools required, capabilities dropped.
- Per-request security overrides are off by default and can only lower limits unless explicitly allowed.
Consequences
Section titled “Consequences”- Safe defaults cost first-run convenience; dev mode exists for local use and logs a loud warning.
- Client-side URL generators (unpic) cannot sign;
restrictedmode is the compromise and must be documented prominently. - Security features need continuous fuzzing and a published security policy (
SECURITY.md)before 1.0. Amended 2026-10-25 (owner, WP-152): the project follows ZeroVer, so there is no 1.0 (docs/RELEASE.md “Versioning”).SECURITY.mdis published before the repository goes public.