CVE-2026-73087: Dozzle SSRF Guard Bypass Vulnerability
LOWCVE-2026-73087 is a LOW ssrf guard bypass vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting Dozzle libraries in the Go ecosystem. The issue involves ssrf guard bypass via ipv6 transition addresses (6to4/nat64/teredo) in webhook notification dispatcher. Remediation is available by upgrading affected packages to version 1.29.1-0.20260804193351-8cf7ccd5ee04.
CVE-2026-73087 at a Glance
How to Fix CVE-2026-73087
To remediate this vulnerability, upgrade all affected Dozzle dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade github.com/amir20/dozzle to 1.29.1-0.20260804193351-8cf7ccd5ee04
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for github.com/amir20/dozzle
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-73087, inspect your project dependencies for Dozzle:
inspect dependencies for github.com/amir20/dozzle
Analyze the terminal output to locate any version of Dozzle in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.29.1-0.20260804193351-8cf7ccd5ee04), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. In Dozzle, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-73087 Affected Dozzle Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
github.com/amir20/dozzle
|
Go |
< 1.29.1-0.20260804193351-8cf7ccd5ee04
|
1.29.1-0.20260804193351-8cf7ccd5ee04
|
References
Frequently Asked Questions
What is CVE-2026-73087?
Which Dozzle versions are affected?
What version fixes CVE-2026-73087?
Is github.com/amir20/dozzle affected?
What CWE is associated with CVE-2026-73087?
How can I check Go dependencies for CVE-2026-73087?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-p2w3-6x73-2f6x",
"modified" : "2026-09-08T18:11:56Z",
"published" : "2026-09-08T18:11:56Z",
"aliases" : [ "CVE-2026-73087" ],
"summary" : "Dozzle: SSRF guard bypass via IPv6 transition addresses (6to4/NAT64/Teredo) in webhook notification dispatcher",
"details" : "## Summary\n\nThe `isBlockedIP` SSRF guard in Dozzle's webhook notification dispatcher blocks loopback, link-local, multicast, and unspecified addresses but does not recognize IPv6 transition mechanism addresses (RFC 3056 6to4, RFC 6052 NAT64, RFC 4380 Teredo) that embed arbitrary IPv4 addresses. An authenticated user can bypass the guard to reach loopback services, cloud metadata endpoints (169.254.169.254), and other blocked ranges via webhook notification URLs.\n\n## Affected component / versions\n\n- Package: `github.com/amir20/dozzle`\n- Affected versions: all versions with SSRF guard (current HEAD [`b9df313`](https://github.com/amir20/dozzle/commit/b9df31356fc024e6768a1aac605844dc041d95ee))\n- Vulnerable code: `internal/notification/dispatcher/webhook.go`\n\n## Details\n\n### Root cause (CWE-918)\n\n[`internal/notification/dispatcher/webhook.go:32-51`](https://github.com/amir20/dozzle/blob/b9df31356fc024e6768a1aac605844dc041d95ee/internal/notification/dispatcher/webhook.go#L32-L51):\n\n```go\nfunc isBlockedIP(ip net.IP) bool {\n\tif ip.IsLoopback() ||\n\t\tip.IsLinkLocalUnicast() ||\n\t\tip.IsLinkLocalMulticast() ||\n\t\tip.IsMulticast() ||\n\t\tip.IsInterfaceLocalMulticast() ||\n\t\tip.IsUnspecified() {\n\t\treturn true\n\t}\n\tif v4 := ip.To4(); v4 != nil && zeroNetV4.Contains(v4) {\n\t\treturn true\n\t}\n\tif ip.Equal(net.IPv4bcast) {\n\t\treturn true\n\t}\n\treturn false\n}\n```\n\nThe guard intentionally allows RFC 1918 private ranges for self-hosted webhook targets, but blocks loopback (127.0.0.0/8, ::1), link-local (169.254.0.0/16, fe80::/10), and other non-routable addresses. IPv6 transition mechanism addresses bypass all these checks:\n\n| Mechanism | Prefix | Embeds | `isBlockedIP` result |\n|-----------|--------|--------|---------------------|\n| 6to4 | `2002::/16` | any IPv4 in bits 16-47 | `false` |\n| NAT64 WKP | `64:ff9b::/96` | any IPv4 in bits 96-127 | `false` |\n| Teredo | `2001:0000::/32` | any IPv4 in bits 96-127 | `false` |\n\n### Reachability / trust boundary\n\nThe `safeDialContext` function (line 53) resolves hostnames and checks each IP against `isBlockedIP` before establishing a TCP connection. This is used as the `DialContext` for the webhook HTTP client (line 115).\n\nWebhook URLs are configured by authenticated Dozzle users through the notification settings UI. The guard exists to prevent authenticated users from using webhook delivery as a proxy to reach the host machine's loopback services or cloud metadata endpoint.\n\n### Attack chain\n\n1. Authenticated user creates a webhook notification with URL `http://[2002:7f00:0001::1]:8080/` (6to4 embedding 127.0.0.1)\n2. When a notification triggers, Dozzle's webhook dispatcher calls `safeDialContext`\n3. The IPv6 address `2002:7f00:0001::1` is checked against `isBlockedIP` -- all predicates return false\n4. Connection proceeds to the 6to4 relay which routes to 127.0.0.1\n5. The webhook POST reaches the host's loopback services\n\n## Impact\n\nAn authenticated user can bypass the SSRF guard to:\n\n- Reach cloud metadata service at 169.254.169.254 via `2002:a9fe:a9fe::1` (6to4) to steal instance credentials\n- Reach localhost services via `64:ff9b::7f00:1` (NAT64) or `2002:7f00:0001::1` (6to4)\n- The webhook response body is logged at debug level but not returned to the user, making this a semi-blind SSRF (status code is returned)\n\nNote: RFC 1918 private ranges are intentionally allowed by the guard. This bypass specifically targets the blocked ranges (loopback and link-local/metadata) that the guard explicitly intends to prevent.\n\n## Proof of concept\n\nBypass vectors:\n\n```\n# 6to4 embedding 127.0.0.1 (bypasses IsLoopback)\nhttp://[2002:7f00:0001::1]:8080/\n\n# NAT64 embedding 169.254.169.254 (bypasses IsLinkLocalUnicast)\nhttp://[64:ff9b::a9fe:a9fe]/latest/meta-data/\n\n# 6to4 embedding 169.254.169.254 (bypasses IsLinkLocalUnicast)\nhttp://[2002:a9fe:a9fe::1]/latest/meta-data/\n\n# Teredo embedding 127.0.0.1\nhttp://[2001:0000:dead:beef:0000:0000:7f00:0001]:8080/\n```\n\nVerification that `isBlockedIP` returns false for all vectors:\n\n```go\npackage main\n\nimport (\n \"fmt\"\n \"net\"\n)\n\nfunc isBlockedIP(ip net.IP) bool {\n return ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() ||\n ip.IsMulticast() || ip.IsInterfaceLocalMulticast() || ip.IsUnspecified()\n}\n\nfunc main() {\n for _, v := range []string{\n \"2002:7f00:0001::1\", // 6to4 -> 127.0.0.1\n \"64:ff9b::a9fe:a9fe\", // NAT64 -> 169.254.169.254\n \"2002:a9fe:a9fe::1\", // 6to4 -> 169.254.169.254\n } {\n ip := net.ParseIP(v)\n fmt.Printf(\"%-35s blocked=%v\\n\", v, isBlockedIP(ip))\n }\n}\n// Output: all false\n```\n\n## Remediation\n\nAdd IPv6 transition mechanism prefix checks to `isBlockedIP`:\n\n```go\nfunc isBlockedIP(ip net.IP) bool {\n\t// ... existing checks ...\n\n\t// IPv6 transition mechanisms embedding arbitrary IPv4\n\tif len(ip) == net.IPv6len {\n\t\tif ip[0] == 0x20 && ip[1] == 0x02 { return true } // 6to4\n\t\tif ip[0] == 0x00 && ip[1] == 0x64 && ip[2] == 0xff && ip[3] == 0x9b { return true } // NAT64\n\t\tif ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && ip[3] == 0x00 { return true } // Teredo\n\t}\n\treturn false\n}\n```\n\n## Credit\n\nReported by tonghuaroot (tonghuaroot@gmail.com).",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/amir20/dozzle"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.29.1-0.20260804193351-8cf7ccd5ee04"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/amir20/dozzle/security/advisories/GHSA-p2w3-6x73-2f6x"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-73087"
}, {
"type" : "WEB",
"url" : "https://github.com/amir20/dozzle/pull/4887"
}, {
"type" : "WEB",
"url" : "https://github.com/amir20/dozzle/commit/8cf7ccd5ee041ecaea92b49951793d4d2393761f"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/amir20/dozzle"
}, {
"type" : "WEB",
"url" : "https://github.com/amir20/dozzle/releases/tag/v10.6.15"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-918" ],
"severity" : "LOW",
"github_reviewed" : true,
"github_reviewed_at" : "2026-09-08T18:11:56Z",
"nvd_published_at" : "2026-08-11T17:19:16Z"
}
}