{"record":{"id":"91911a0f07c3e87b","repo":"JuliusBrussee/caveman","slug":"ssrf-destination-s-for-host-q-is-a-private-ad-91911a","errorCode":null,"errorMessage":"ssrf: destination %s (for host %q) is a private address; add it to the allowlist to permit it","messagePattern":"ssrf: destination (.+?) \\(for host %q\\) is a private address; add it to the allowlist to permit it","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/ssrf/ssrf.go","lineNumber":307,"sourceCode":"\t}\n\n\tfor _, p := range blockedPrefixes {\n\t\tif p.Contains(addr) {\n\t\t\t// These ranges (link-local/metadata, ULA outside the narrow local-TUN\n\t\t\t// exception, multicast, unspecified, documentation) are absolutely\n\t\t\t// blocked — no allowlist escape in any mode.\n\t\t\treturn fmt.Errorf(\"ssrf: destination %s (for host %q) is in blocked range %s\", addr, host, p)\n\t\t}\n\t}\n\n\tif inRFC1918(addr) {\n\t\tif cfg.ManagedMode {\n\t\t\treturn fmt.Errorf(\"ssrf: destination %s (for host %q) is a private address blocked in managed mode\", addr, host)\n\t\t}\n\t\t// In self-hosted mode, RFC1918 is blocked unless the original hostname\n\t\t// OR the resolved IP literal appears in the allowlist.\n\t\tif !isInAllowList(host, port, cfg.AllowList) && !isInAllowList(addr.String(), port, cfg.AllowList) {\n\t\t\treturn fmt.Errorf(\"ssrf: destination %s (for host %q) is a private address; add it to the allowlist to permit it\", addr, host)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc inRFC1918(addr netip.Addr) bool {\n\tfor _, p := range privateRFC1918 {\n\t\tif p.Contains(addr) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc isInAllowList(host, port string, list []string) bool {\n\th := strings.ToLower(strings.Trim(host, \"[]\"))\n\tfor _, entry := range list {\n\t\traw := strings.TrimSpace(entry)","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/shared/platform/ssrf/ssrf.go#L289-L325","documentation":"checkAddr in ssrf: the address is RFC1918 private and mode is self-hosted (ManagedMode false). Private ranges are blocked by default there too, but the operator can opt in per-target: the original hostname OR the resolved IP literal must appear in cfg.AllowList for that port.","triggerScenarios":"Validating/dialing 10.x/172.16-31.x/192.168.x in self-hosted mode when neither the hostname nor the IP literal has a matching AllowList entry (host:port or ip:port).","commonSituations":"Self-hosted install pointing integrations at an internal NAS, database host, or cluster service (e.g. 192.168.1.20:9200) without allowlisting; hostname allowlisted but on a different port than dialed.","solutions":["Add the exact 'host:port' or 'ip:port' to cfg.AllowList (e.g. '192.168.1.20:9200').","Confirm the port in the allowlist entry matches the dialed port exactly — entries are port-specific.","Keep entries minimal: allowlist the specific service, not the whole /8 by hostname wildcard."],"exampleFix":"// before\ncfg := ssrf.Config{ManagedMode: false}\nssrf.ValidateURL(ctx, \"https://192.168.1.20:9200/index\", cfg) // blocked\n\n// after\ncfg := ssrf.Config{ManagedMode: false, AllowList: []string{\"192.168.1.20:9200\"}}\nssrf.ValidateURL(ctx, \"https://192.168.1.20:9200/index\", cfg)","handlingStrategy":"validation","validationCode":"target := net.JoinHostPort(host, port)\nipTarget := net.JoinHostPort(ipLiteral, port)\nif !contains(cfg.AllowList, target) && !contains(cfg.AllowList, ipTarget) {\n    return fmt.Errorf(\"private target %s must be allowlisted as 'host:port' or 'ip:port'\", target)\n}","typeGuard":null,"tryCatchPattern":"if err := ssrf.ValidateURL(ctx, raw, cfg); err != nil {\n    if !cfg.ManagedMode && strings.Contains(err.Error(), \"add it to the allowlist\") {\n        // guide the operator to add host:port to AllowList, then re-validate\n    }\n}","preventionTips":["Allowlist entries are port-specific — match the exact port being dialed.","Prefer allowlisting a stable internal hostname over a re-assignable pod IP."],"tags":["ssrf","network","rfc1918","allowlist","go"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}