JuliusBrussee/caveman · error
ssrf: destination %s (for host %q) is a private address bloc
Error message
ssrf: destination %s (for host %q) is a private address blocked in managed mode
What it means
checkAddr in ssrf: the address is RFC1918 private (10/8, 172.16/12, 192.168/16) and cfg.ManagedMode is true. Managed (multi-tenant) mode blocks all private ranges categorically — a tenant must not be able to probe the operator's internal network — with no allowlist bypass.
Source
Thrown at shared/platform/ssrf/ssrf.go:302
if !cfg.ManagedMode {
return nil
}
return fmt.Errorf("ssrf: destination %s (for host %q) is in blocked range %s", addr, host, p)
}
}
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 it to the allowlist to permit it", addr, host)
}
}
return nil
}
func inRFC1918(addr netip.Addr) bool {
for _, p := range privateRFC1918 {
if p.Contains(addr) {
return true
}
}
return false
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Expose the internal service through a public/LB endpoint (https, port 443) and use that URL.
- If this deployment is actually self-hosted/single-tenant, set ManagedMode false — then the allowlist path applies.
- Never attempt to bypass: in managed mode the block is the security boundary.
Example fix
// before (managed deployment)
cfg := ssrf.Config{ManagedMode: true}
ssrf.ValidateURL(ctx, "https://10.0.4.12/api", cfg) // blocked
// after: use the public endpoint
ssrf.ValidateURL(ctx, "https://api.internal.example.com/api", cfg) Defensive patterns
Strategy: validation
Validate before calling
if cfg.ManagedMode {
if ip := net.ParseIP(host); ip != nil && ip.IsPrivate() {
return fmt.Errorf("private addresses are not dialable in managed mode")
}
} Try / catch
if err := ssrf.ValidateURL(ctx, raw, cfg); err != nil {
if cfg.ManagedMode && strings.Contains(err.Error(), "private address blocked in managed mode") {
// ask for the public endpoint URL; no configuration fix exists
}
} Prevention
- In managed deployments, expose internal services through public LBs and validate endpoints at intake.
- Do not copy self-hosted config (private IPs) into managed environments.
When it happens
Trigger: Validating or dialing any 10.x, 172.16-31.x, or 192.168.x address while ManagedMode is true, including via hostnames that resolve into those ranges.
Common situations: SaaS/managed deployment where a user configures a webhook to an internal address; operator mistakenly runs managed-mode config on-prem where the only reachable systems are RFC1918.
Related errors
- ssrf: scheme %q not permitted (managed mode requires https)
- ssrf: host %q is blocked (loopback)
- ssrf: destination %s (for host %q) is in blocked range %s
- ssrf: destination %s (for host %q) is a private address; add
- ssrf: credentials embedded in URL are forbidden
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c0a70ca672bb5cd5.
Report an issue: GitHub.