JuliusBrussee/caveman · error
ssrf: destination %s (for host %q) is a private address; add
Error message
ssrf: destination %s (for host %q) is a private address; add %s to the SSRF allowlist (CAVE_SSRF_ALLOWLIST) to permit it
What it means
checkAddr blocked an RFC1918 private destination in self-hosted mode because no allowlist entry matches. The message names CAVE_SSRF_ALLOWLIST so operators with legitimate internal endpoints can opt in explicitly.
Source
Thrown at shared/platform/ssrf/ssrf.go:316
}
for _, p := range blockedPrefixes {
if p.Contains(addr) {
// These ranges (link-local/metadata, ULA outside the narrow local-TUN
// exception, multicast, unspecified, documentation) are absolutely
// blocked — no allowlist escape in any mode.
return fmt.Errorf("ssrf: destination %s (for host %q) is in blocked range %s", addr, host, p)
}
}
if inRFC1918(addr) {
if cfg.ManagedMode {
return fmt.Errorf("ssrf: destination %s (for host %q) is a private address blocked in managed mode", addr, host)
}
// In self-hosted mode, RFC1918 is blocked unless the original hostname
// OR the resolved IP literal appears in the allowlist.
if !isInAllowList(host, port, cfg.AllowList) && !isInAllowList(addr.String(), port, cfg.AllowList) {
return fmt.Errorf("ssrf: destination %s (for host %q) is a private address; add %s to the SSRF allowlist (CAVE_SSRF_ALLOWLIST) to permit it", addr, host, allowListSuggestion(addr, port))
}
}
return nil
}
// allowListSuggestion renders the allowlist entry to advise for a blocked
// destination. It must be an entry isInAllowList would actually accept at BOTH
// stages: ValidateHost pre-flights with an empty port, so JoinHostPort would
// emit a trailing-colon token like "127.0.0.1:" that matches only the
// port-less stage — an operator following that advice literally relaxes the
// pre-flight guard, is blocked again at dial time by a second message naming a
// different token, and leaves a stale weakening entry behind. The bare address
// form is the one entry that matches every stage.
func allowListSuggestion(addr netip.Addr, port string) string {
if port == "" {
return addr.String()
}
return net.JoinHostPort(addr.String(), port)View on GitHub (pinned to 766dce6b13)
Solutions
- Add the original hostname or its IP to CAVE_SSRF_ALLOWLIST if the internal endpoint is intentional
- Otherwise point the request at the public address of the service
- Verify the allowlist entry format matches host and port
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at shared/platform/ssrf/ssrf.go:316 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/cb276272fe327f79.
Report an issue: GitHub.