Gotenberg allows Chromium URL conversion routes to read arbitrary files under /tmp via file:// scheme
Date: 2026-05
Affected: go/github.com/gotenberg/gotenberg/v8
Attack vector: ssrf
Category: vulnerability-disclosure
Severity: Medium
CVE: CVE-2026-42597
CWE: CWE-73
CWE-918
CVSS: 5.9 (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N)

## Summary The `/forms/chromium/convert/url` and `/forms/chromium/screenshot/url` routes accept `url=file:///tmp/...` from anonymous callers. The default Chromium deny-list intentionally exempts `file:///tmp/` so HTML/Markdown routes can load their own request-local assets, and those routes apply a per-request `AllowedFilePrefixes` guard to scope the read. The URL routes never set `AllowedFilePrefixes`, so the scope guard silently skips. Alice enumerates `/tmp/`, walks Gotenberg's per-request working directories, and reads the raw source files of other in-flight conversions as rendered PDF output. ## Details The default deny-list regex at `pkg/modules/chromium/chromium.go:449` uses a negative lookahead to exempt `/tmp/`: ```go fs.StringSlice("chromium-deny-list", []string{`^file:(?!//\/tmp/).*`}, "Set the denied URLs for Chromium using regular expressions - supports multiple values") ``` `pkg/gotenberg/outbound.go:185-187` short-circuits IP validation for non-HTTP schemes: ```go if !httpLikeScheme(parsed.Scheme) { return outboundDecision{}, nil } ``` So any `file:///tmp/...` URL passes `FilterOutboundURL` cleanly. The HTML route pairs the exemption with a per-request scope guard (`pkg/modules/chromium/routes.go:518`): ```go options.AllowedFilePrefixes = []string{ctx.DirPath()} ``` and the CDP `Fetch.requestPaused` handler enforces the scope (`pkg/modules/chromium/events.go:65-78`): ```go if allow && strings.HasPrefix(e.Request.URL, "file://") && len(opt


Mitigations:

Architectural layers (MAESTRO):