Fix #96: private-IP range gaps #105

Merged
crueber merged 2 commits from fix/issue-96 into main 2026-09-05 03:24:46 +00:00
Owner

Fixes #96. Verdict: the gap was REAL — PR #88's shared internal/egress table covered 198.18.0.0/15 + TEST-NET-1/2/3 (+ mapped-v6), but internal/repoimport/url.go:isPrivateIP kept its own hand-rolled list and never delegated to it. Fix: isPrivateIP now denies loopback explicitly (egress allows it for dev webhooks; import sources must never resolve inward) and defers everything else to egress.BlockedIP; unparseable input fails closed. Table tests extended in both packages (incl. mapped-v6 forms for all four listed ranges); docs/features/10 SSRF paragraph + Decisions updated in the same change. Evidence: go test -race green for both packages; cover repoimport 95.7%, egress 97.6%.

Fixes #96. Verdict: the gap was REAL — PR #88's shared internal/egress table covered 198.18.0.0/15 + TEST-NET-1/2/3 (+ mapped-v6), but internal/repoimport/url.go:isPrivateIP kept its own hand-rolled list and never delegated to it. Fix: isPrivateIP now denies loopback explicitly (egress allows it for dev webhooks; import sources must never resolve inward) and defers everything else to egress.BlockedIP; unparseable input fails closed. Table tests extended in both packages (incl. mapped-v6 forms for all four listed ranges); docs/features/10 SSRF paragraph + Decisions updated in the same change. Evidence: go test -race green for both packages; cover repoimport 95.7%, egress 97.6%.
internal/repoimport/url.go kept its own range list and missed
198.18.0.0/15, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 (plus
240.0.0.0/4, ::/128, 2001:db8::/32). PR #88's internal/egress table
covered them, but url.go never used it. isPrivateIP now denies
loopback explicitly (egress allows it for dev webhooks; import
sources must never resolve inward) and defers the rest to
egress.BlockedIP; unparseable input fails closed. Table tests
extended in both packages; doc 10 SSRF paragraph + Decisions
updated in the same change.
checkPrivate still carried the pre-delegation range enumeration;
point it at isPrivateIP/shared table. Pin unparseable input
(net.ParseIP nil) failing closed in TestIsPrivateIPShapes.
Sign in to join this conversation.
No description provided.