Add an egress CIDR allowlist to the SSRF guard (closes #204) (#217)
All checks were successful
check / check (push) Successful in 3m1s

This commit was merged in pull request #217.
This commit is contained in:
2026-08-20 10:34:42 +02:00
parent f0512f1c3c
commit 03cd1859d7
17 changed files with 1244 additions and 61 deletions

View File

@@ -5,6 +5,7 @@ import (
"log/slog"
"net"
"net/http"
"net/netip"
"time"
"go.uber.org/fx"
@@ -38,6 +39,26 @@ func ExportIsBlockedIP(ip net.IP) bool {
return isBlockedIP(ip)
}
// NewTestGuard builds an SSRF Guard from an explicit egress
// allowlist, without going through config. Passing no prefixes
// yields the default guard, which blocks every private/reserved
// range.
func NewTestGuard(allowed ...netip.Prefix) *Guard {
return &Guard{allowed: allowed}
}
// ExportCheckIP exposes the guard's single decision point, so a
// test can assert the policy both the validator and the dialer
// inherit without needing a live destination.
func (g *Guard) ExportCheckIP(ip net.IP) error {
return g.checkIP(ip)
}
// ExportAlwaysBlockedNetworks exposes alwaysBlockedNetworks.
func ExportAlwaysBlockedNetworks() []*net.IPNet {
return alwaysBlockedNetworks
}
// ExportBlockedNetworks exposes blockedNetworks.
func ExportBlockedNetworks() []*net.IPNet {
return blockedNetworks