diff --git a/pkgs/by-name/ma/mailpit/CVE-2026-84697.patch b/pkgs/by-name/ma/mailpit/CVE-2026-84697.patch new file mode 100644 index 0000000000000..87773eddaa98c --- /dev/null +++ b/pkgs/by-name/ma/mailpit/CVE-2026-84697.patch @@ -0,0 +1,132 @@ +From a02821bf3424da9196e156c422370f4868a1dff2 Mon Sep 17 00:00:00 2001 +From: Ralph Slooten +Date: Sat, 29 Aug 2026 20:35:34 +1200 +Subject: [PATCH] Fix: Block Azure WireServer, IPv4-translated prefix and + additional reserved ranges in SSRF deny-list + +diff --git a/internal/tools/net.go b/internal/tools/net.go +--- a/internal/tools/net.go ++++ b/internal/tools/net.go +@@ -16,22 +16,26 @@ var ( + // IPv6 transition prefixes that embed an IPv4 destination. Go's net.IP.Is* family + // does not decode these, so an IPv6 literal of one of these forms can carry a + // private/link-local IPv4 destination past the stdlib checks. See golang/go#79925. +- nat64WellKnown = mustCIDR("64:ff9b::/96") // RFC 6052 +- nat64LocalUse = mustCIDR("64:ff9b:1::/48") // RFC 8215 +- sixToFour = mustCIDR("2002::/16") // RFC 3056 +- teredo = mustCIDR("2001::/32") // RFC 4380 +- ipv4Compatible = mustCIDR("::/96") // RFC 4291 §2.5.5.1 ++ nat64WellKnown = mustCIDR("64:ff9b::/96") // RFC 6052 ++ nat64LocalUse = mustCIDR("64:ff9b:1::/48") // RFC 8215 ++ sixToFour = mustCIDR("2002::/16") // RFC 3056 ++ teredo = mustCIDR("2001::/32") // RFC 4380 ++ ipv4Compatible = mustCIDR("::/96") // RFC 4291 §2.5.5.1 ++ ipv4Translated = mustCIDR("::ffff:0:0:0/96") // RFC 2765/6145 — IPv4-translated + // IPv4-mapped IPv6 (::ffff:0:0/96, RFC 4291 §2.5.5.2) is normalised by net.IP.To4, + // so the stdlib Is* checks above already see the embedded IPv4 - no decode needed. + + // Direct IPv4 special-use ranges not covered by Go's stdlib Is* family. + // See https://www.iana.org/assignments/iana-ipv4-special-registry/ +- benchmarkRange = mustCIDR("198.18.0.0/15") // RFC 2544 — benchmarking, not globally reachable +- ietfProtocol = mustCIDR("192.0.0.0/24") // RFC 6890 — IETF protocol assignments, not globally reachable +- testNet1 = mustCIDR("192.0.2.0/24") // RFC 5737 — documentation (TEST-NET-1), not globally reachable +- testNet2 = mustCIDR("198.51.100.0/24") // RFC 5737 — documentation (TEST-NET-2), not globally reachable +- testNet3 = mustCIDR("203.0.113.0/24") // RFC 5737 — documentation (TEST-NET-3), not globally reachable +- reservedForFuture = mustCIDR("240.0.0.0/4") // RFC 1112 — reserved for future use, not globally reachable ++ thisNetwork = mustCIDR("0.0.0.0/8") // RFC 1122 — "this network", not globally reachable ++ benchmarkRange = mustCIDR("198.18.0.0/15") // RFC 2544 — benchmarking, not globally reachable ++ ietfProtocol = mustCIDR("192.0.0.0/24") // RFC 6890 — IETF protocol assignments, not globally reachable ++ sixToFourRelay = mustCIDR("192.88.99.0/24") // RFC 7526 — 6to4 relay anycast, deprecated ++ testNet1 = mustCIDR("192.0.2.0/24") // RFC 5737 — documentation (TEST-NET-1), not globally reachable ++ testNet2 = mustCIDR("198.51.100.0/24") // RFC 5737 — documentation (TEST-NET-2), not globally reachable ++ testNet3 = mustCIDR("203.0.113.0/24") // RFC 5737 — documentation (TEST-NET-3), not globally reachable ++ reservedForFuture = mustCIDR("240.0.0.0/4") // RFC 1112 — reserved for future use, not globally reachable ++ azureWireServer = mustCIDR("168.63.129.16/32") // Azure host agent / platform metadata channel + + // Direct IPv6 prefixes outside the scope of Go's stdlib Is* family. + deprecatedSiteLocal = mustCIDR("fec0::/10") // RFC 3879 / RFC 4291 §2.5.7 — deprecated, still routable on dual-stack hosts +@@ -48,17 +52,20 @@ func mustCIDR(s string) *net.IPNet { + // IsInternalIP checks if the given IP address is an internal IP address (e.g., loopback, private, link-local, or multicast). + // IsLoopback - 127.0.0.0/8, ::1 + // IsPrivate - 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7 +-// IsLinkLocalUnicast - 169.254.0.0/16, fe80::/10 (covers cloud metadata 169.254.169.254) ++// IsLinkLocalUnicast - 169.254.0.0/16, fe80::/10 (covers AWS/GCP cloud metadata 169.254.169.254) + // IsLinkLocalMulticast - 224.0.0.0/24, ff02::/16 + // IsUnspecified - 0.0.0.0, :: + // IsMulticast - 224.0.0.0/4, ff00::/8 ++// This network - 0.0.0.0/8 (RFC 1122) + // CGNAT - 100.64.0.0/10 (RFC 6598) (Carrier-Grade NAT) ++// Azure WireServer - 168.63.129.16/32 (platform metadata channel) ++// 6to4 relay anycast - 192.88.99.0/24 (RFC 7526, deprecated) + // Benchmarking - 198.18.0.0/15 (RFC 2544) + // IETF Protocol Assignments - 192.0.0.0/24 (RFC 6890) + // Documentation - 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 (RFC 5737) + // Reserved for Future Use - 240.0.0.0/4 (RFC 1112) + // IPv6 transition forms - NAT64 (RFC 6052/8215), 6to4 (RFC 3056), Teredo (RFC 4380), +-// IPv4-compatible (RFC 4291) - re-checked against their embedded IPv4. ++// IPv4-compatible (RFC 4291), IPv4-translated (RFC 2765/6145) - re-checked against their embedded IPv4. + func IsInternalIP(ip net.IP) bool { + if ip.IsLoopback() || + ip.IsPrivate() || +@@ -67,12 +74,15 @@ func IsInternalIP(ip net.IP) bool { + ip.IsUnspecified() || + ip.IsMulticast() || + cgnatRange.Contains(ip) || ++ thisNetwork.Contains(ip) || + benchmarkRange.Contains(ip) || + ietfProtocol.Contains(ip) || ++ sixToFourRelay.Contains(ip) || + testNet1.Contains(ip) || + testNet2.Contains(ip) || + testNet3.Contains(ip) || + reservedForFuture.Contains(ip) || ++ azureWireServer.Contains(ip) || + deprecatedSiteLocal.Contains(ip) || + documentationPrefix.Contains(ip) { + return true +@@ -103,7 +113,7 @@ func embeddedIPv4(ip net.IP) (net.IP, bool) { + + switch { + case nat64WellKnown.Contains(ip16), nat64LocalUse.Contains(ip16), +- ipv4Compatible.Contains(ip16): ++ ipv4Compatible.Contains(ip16), ipv4Translated.Contains(ip16): + // Last 32 bits are the embedded IPv4. + return net.IPv4(ip16[12], ip16[13], ip16[14], ip16[15]).To4(), true + case sixToFour.Contains(ip16): +diff --git a/internal/tools/tools_test.go b/internal/tools/tools_test.go +--- a/internal/tools/tools_test.go ++++ b/internal/tools/tools_test.go +@@ -27,6 +27,10 @@ func TestIsInternalIP(t *testing.T) { + "203.0.113.1", // TEST-NET-3 (RFC 5737) + "240.0.0.1", // reserved for future use (RFC 1112) + "255.255.255.254", // reserved for future use end ++ "0.1.2.3", // this-network 0.0.0.0/8 (RFC 1122) ++ "168.63.129.16", // Azure WireServer / platform metadata channel ++ "192.88.99.1", // 6to4 relay anycast (RFC 7526, deprecated) ++ "192.88.99.254", // 6to4 relay anycast end + // IPv6 transition forms embedding an internal IPv4 destination — golang/go#79925. + "64:ff9b::a9fe:a9fe", // NAT64 well-known (RFC 6052) wrapping 169.254.169.254 + "64:ff9b:1::a9fe:a9fe", // NAT64 local-use (RFC 8215) wrapping 169.254.169.254 +@@ -40,6 +44,9 @@ func TestIsInternalIP(t *testing.T) { + "fec0::1", // deprecated site-local (RFC 3879 / RFC 4291 §2.5.7) + "2001:db8::1", // documentation prefix (RFC 3849) + "2001:db8::5efe:0808:0808", // documentation prefix (blocked regardless of embedded IPv4) ++ "::ffff:0:7f00:1", // IPv4-translated (RFC 2765/6145) wrapping 127.0.0.1 ++ "::ffff:0:a9fe:a9fe", // IPv4-translated (RFC 2765/6145) wrapping 169.254.169.254 ++ "::ffff:0:a00:1", // IPv4-translated (RFC 2765/6145) wrapping 10.0.0.1 + } + external := []string{ + "8.8.8.8", +@@ -53,6 +60,12 @@ func TestIsInternalIP(t *testing.T) { + "2001:4860:4860::8888", // Google public DNS over IPv6 + "2002:0808:0808::", // 6to4 wrapping 8.8.8.8 (public IPv4) + "64:ff9b::0808:0808", // NAT64 wrapping 8.8.8.8 (public IPv4) ++ "::ffff:0:0808:0808", // IPv4-translated wrapping 8.8.8.8 (public IPv4) ++ "1.0.0.1", // just outside this-network 0.0.0.0/8 ++ "168.63.129.15", // just before Azure WireServer ++ "168.63.129.17", // just after Azure WireServer ++ "192.88.98.255", // just before 6to4 relay anycast range ++ "192.89.0.0", // just after 6to4 relay anycast range + } + + for _, s := range internal { diff --git a/pkgs/by-name/ma/mailpit/package.nix b/pkgs/by-name/ma/mailpit/package.nix index 4af3b4aa66d86..a89c6a629c3fe 100644 --- a/pkgs/by-name/ma/mailpit/package.nix +++ b/pkgs/by-name/ma/mailpit/package.nix @@ -70,6 +70,8 @@ buildGoModule (finalAttrs: { pname = "mailpit"; inherit src version vendorHash; + patches = [ ./CVE-2026-84697.patch ]; + env.CGO_ENABLED = 0; ldflags = [