JuliusBrussee/caveman · error
ssrf: invalid dial address
Error message
ssrf: invalid dial address
What it means
Dial-time enforcement inside dialContextWith: the address being connected to failed validation before the dialer was invoked. The hostname was resolved and every returned address is checked against SSRF block lists, then only a validated IP literal is dialed; this error means that validation failed at dial time.
Source
Thrown at shared/platform/ssrf/ssrf.go:398
dialer := &net.Dialer{
Timeout: connectTimeout,
KeepAlive: 30 * time.Second,
}
return dialContextWith(cfg, net.DefaultResolver.LookupNetIP, dialer.DialContext)
}
type lookupNetIPFunc func(context.Context, string, string) ([]netip.Addr, error)
type rawDialContextFunc func(context.Context, string, string) (net.Conn, error)
// dialContextWith resolves each hostname exactly once, validates every returned
// address, then dials a validated IP literal. net.Transport passes hostnames to
// DialContext; validating the hostname and handing it to net.Dialer would cause
// a second DNS lookup and reopen the DNS-rebinding window.
func dialContextWith(cfg Config, lookup lookupNetIPFunc, dial rawDialContextFunc) func(ctx context.Context, network, addr string) (net.Conn, error) {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, errors.New("ssrf: invalid dial address")
}
if err := validateHostInput(host); err != nil {
return nil, err
}
if cfg.ManagedMode && port != "443" {
return nil, errors.New("ssrf: managed mode requires port 443")
}
if parsed, parseErr := netip.ParseAddr(host); parseErr == nil {
parsed = parsed.WithZone("").Unmap()
if err := checkAddr(parsed, host, port, cfg); err != nil {
return nil, err
}
return dial(ctx, network, net.JoinHostPort(parsed.String(), port))
}
if strings.EqualFold(host, "localhost") && !(!cfg.ManagedMode && isInAllowList(host, port, cfg.AllowList)) {
return nil, fmt.Errorf("ssrf: host %q is blocked (loopback)", host)View on GitHub (pinned to 766dce6b13)
Solutions
- Compare the dial-time failure with the pre-flight ValidateURL result to find where DNS rebinding or a changed hostname bypassed pre-flight checks
- Pin or re-validate the upstream configuration before retrying the connection
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at shared/platform/ssrf/ssrf.go:398 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/c026b4a4a90fa468.
Report an issue: GitHub.