From 30e65dce53905cf6ff45560289a09543fadbb37a Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Fri, 2 Oct 2026 00:21:35 +0200 Subject: [PATCH] State what the default blocklist covers (closes #244) The README's egress section and the comment above blockedNetworks now state what the default blocklist covers: the IPv4 private and reserved ranges, IPv6 loopback, unique local and link-local addresses, and certain public addresses, each added only because it hands credentials, user data or bootstrap material to whatever can reach it without the caller presenting anything. That is the same material as the rule above alwaysBlockedNetworks, so a future candidate can be accepted or refused against one rule. A provider's other public addresses, such as 161.26.0.0/16 and 166.8.0.0/14, are not refused. Docs and a comment only; the lists are unchanged. Model: opus-5-5 --- README.md | 15 +++++++++++++++ internal/delivery/ssrf.go | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/README.md b/README.md index eed7d55..fca4858 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,21 @@ public cloud metadata addresses: currently only `168.63.129.16`, Azure's WireServer, which serves an Azure VM its credentials. Because it is a public address, listing it in `ALLOWED_EGRESS_CIDRS` reopens it. +That is all the default blocklist covers: the IPv4 private and reserved +ranges; of IPv6, only loopback (`::1`), unique local addresses +(`fc00::/7`) and link-local addresses (`fe80::/10`); and certain public +addresses. A public address belongs on the default blocklist only if it +hands credentials, user data or bootstrap material to whatever can reach +it, without the caller presenting anything. A provider's other public +addresses are not refused. IBM Cloud, for example, serves its package +mirrors, time servers and object storage on `161.26.0.0/16`, and the +private endpoints of its own cloud services on `166.8.0.0/14`. Neither +range hands out credentials that way: the token service among those +endpoints issues a token only in exchange for something the caller +presents, such as an API key. Reaching these services can be a +legitimate delivery, and every cloud has some, so a partial list would +promise coverage it does not give. + That default is also inconvenient for the thing webhooker is mostly for: taking a public webhook and forwarding it to something on your own network. A container on the same Docker network, a box on `10.x`, a diff --git a/internal/delivery/ssrf.go b/internal/delivery/ssrf.go index 0fa73b3..547c1e6 100644 --- a/internal/delivery/ssrf.go +++ b/internal/delivery/ssrf.go @@ -43,6 +43,13 @@ var ( // permit specific blocks out of this set with // ALLOWED_EGRESS_CIDRS; see Guard. // +// A public address belongs on the default blocklist only if it +// hands credentials, user data or bootstrap material to whatever +// can reach it, without the caller presenting anything. A +// provider's other public addresses are not refused, since +// reaching them can be legitimate and no list of them could be +// complete. +// //nolint:gochecknoglobals // package-level network list is appropriate here var blockedNetworks []*net.IPNet