Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions pkgs/by-name/ma/mailpit/CVE-2026-84697.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
From a02821bf3424da9196e156c422370f4868a1dff2 Mon Sep 17 00:00:00 2001
From: Ralph Slooten <axllent@gmail.com>
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 {
2 changes: 2 additions & 0 deletions pkgs/by-name/ma/mailpit/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ buildGoModule (finalAttrs: {
pname = "mailpit";
inherit src version vendorHash;

patches = [ ./CVE-2026-84697.patch ];

env.CGO_ENABLED = 0;

ldflags = [
Expand Down
Loading