Verified against main at 61f42e6. This is the "implement blocked networks configuration to extend SSRF protection" P1 item in TODO.md; confirmed genuinely still missing — there is no such config key and no CIDR list anywhere.
The existing protection is sound in structure: validateURL (internal/httpfetcher/httpfetcher.go:322-331) resolves and checks, and ssrfSafeDialer (:412-441) resolves again and re-checks immediately before dialing, so the DNS-rebinding window is correctly closed at the dialer — that part is good and should not be regressed.
The gap is coverage of isPrivateIP (:366-409). It relies on a hardcoded list and does not appear to cover:
100.64.0.0/10 — CGNAT / carrier-grade NAT, routinely used for internal infrastructure
192.0.0.0/24 — IETF protocol assignments
198.18.0.0/15 — benchmark/test range
64:ff9b::/96 — NAT64, which maps straight back onto IPv4 private space
Uncertain, verify before changing: IPv4-mapped IPv6 (::ffff:10.0.0.1) may already be handled, because Go's ip.IsPrivate() calls To4() internally. Confirm with a test rather than assuming in either direction.
Cloud metadata endpoints (169.254.169.254) fall under link-local — confirm that is actually covered, since it is the single highest-value SSRF target in any deployment on a cloud provider.
Definition of done
A blocked_networks (or similarly named, following the descriptive-naming rule) config key accepting a list of CIDRs, merged with the built-in defaults rather than replacing them. Strict parsing: an invalid CIDR aborts startup naming the key and the offending value, per repo policy.
Built-in blocklist extended to cover the ranges above, in both IPv4 and IPv6 forms.
Enforcement stays in ssrfSafeDialer (the authoritative check), not only in validateURL, so the rebinding protection is preserved.
Failing tests first, table-driven over the address families and ranges, including: each newly blocked range, ::ffff:10.0.0.1, 169.254.169.254, and a positive case proving ordinary public addresses still resolve and dial.
A test that an operator-supplied blocked_networks entry is actually enforced by the dialer.
make check green.
Related
Redirect-based SSRF (the CheckRedirect validator at httpfetcher.go:133-143) is currently untested — covered in the separate httpfetcher test-coverage issue, but worth a glance while in this code.
Verified against `main` at `61f42e6`. This is the "implement blocked networks configuration to extend SSRF protection" P1 item in `TODO.md`; confirmed genuinely still missing — there is no such config key and no CIDR list anywhere.
The existing protection is sound in structure: `validateURL` (`internal/httpfetcher/httpfetcher.go:322-331`) resolves and checks, and `ssrfSafeDialer` (`:412-441`) resolves **again** and re-checks immediately before dialing, so the DNS-rebinding window is correctly closed at the dialer — that part is good and should not be regressed.
The gap is coverage of `isPrivateIP` (`:366-409`). It relies on a hardcoded list and does not appear to cover:
- `100.64.0.0/10` — CGNAT / carrier-grade NAT, routinely used for internal infrastructure
- `192.0.0.0/24` — IETF protocol assignments
- `198.18.0.0/15` — benchmark/test range
- `64:ff9b::/96` — NAT64, which maps straight back onto IPv4 private space
**Uncertain, verify before changing:** IPv4-mapped IPv6 (`::ffff:10.0.0.1`) may already be handled, because Go's `ip.IsPrivate()` calls `To4()` internally. Confirm with a test rather than assuming in either direction.
Cloud metadata endpoints (`169.254.169.254`) fall under link-local — confirm that is actually covered, since it is the single highest-value SSRF target in any deployment on a cloud provider.
## Definition of done
1. A `blocked_networks` (or similarly named, following the descriptive-naming rule) config key accepting a list of CIDRs, merged with the built-in defaults rather than replacing them. Strict parsing: an invalid CIDR aborts startup naming the key and the offending value, per repo policy.
2. Built-in blocklist extended to cover the ranges above, in both IPv4 and IPv6 forms.
3. Enforcement stays in `ssrfSafeDialer` (the authoritative check), not only in `validateURL`, so the rebinding protection is preserved.
4. Failing tests first, table-driven over the address families and ranges, including: each newly blocked range, `::ffff:10.0.0.1`, `169.254.169.254`, and a positive case proving ordinary public addresses still resolve and dial.
5. A test that an operator-supplied `blocked_networks` entry is actually enforced by the dialer.
6. `make check` green.
## Related
Redirect-based SSRF (the `CheckRedirect` validator at `httpfetcher.go:133-143`) is currently untested — covered in the separate httpfetcher test-coverage issue, but worth a glance while in this code.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:44:32 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Verified against
mainat61f42e6. This is the "implement blocked networks configuration to extend SSRF protection" P1 item inTODO.md; confirmed genuinely still missing — there is no such config key and no CIDR list anywhere.The existing protection is sound in structure:
validateURL(internal/httpfetcher/httpfetcher.go:322-331) resolves and checks, andssrfSafeDialer(:412-441) resolves again and re-checks immediately before dialing, so the DNS-rebinding window is correctly closed at the dialer — that part is good and should not be regressed.The gap is coverage of
isPrivateIP(:366-409). It relies on a hardcoded list and does not appear to cover:100.64.0.0/10— CGNAT / carrier-grade NAT, routinely used for internal infrastructure192.0.0.0/24— IETF protocol assignments198.18.0.0/15— benchmark/test range64:ff9b::/96— NAT64, which maps straight back onto IPv4 private spaceUncertain, verify before changing: IPv4-mapped IPv6 (
::ffff:10.0.0.1) may already be handled, because Go'sip.IsPrivate()callsTo4()internally. Confirm with a test rather than assuming in either direction.Cloud metadata endpoints (
169.254.169.254) fall under link-local — confirm that is actually covered, since it is the single highest-value SSRF target in any deployment on a cloud provider.Definition of done
blocked_networks(or similarly named, following the descriptive-naming rule) config key accepting a list of CIDRs, merged with the built-in defaults rather than replacing them. Strict parsing: an invalid CIDR aborts startup naming the key and the offending value, per repo policy.ssrfSafeDialer(the authoritative check), not only invalidateURL, so the rebinding protection is preserved.::ffff:10.0.0.1,169.254.169.254, and a positive case proving ordinary public addresses still resolve and dial.blocked_networksentry is actually enforced by the dialer.make checkgreen.Related
Redirect-based SSRF (the
CheckRedirectvalidator athttpfetcher.go:133-143) is currently untested — covered in the separate httpfetcher test-coverage issue, but worth a glance while in this code.