{"record":{"id":"cee29237fc14327e","repo":"gofiber/fiber","slug":"errupstreamhostblocked","errorCode":"ErrUpstreamHostBlocked","errorMessage":"proxy: upstream host resolves to a blocked address","messagePattern":"proxy: upstream host resolves to a blocked address","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/proxy/security.go","lineNumber":61,"sourceCode":"// allocate []byte(\"https\") on every hop.\nvar httpsSchemeBytes = []byte(schemeHTTPS)\n\n// Sentinel errors returned when an upstream target violates the configured\n// proxy security policy.\nvar (\n\t// ErrUpstreamSchemeNotAllowed is returned when the proxied URL uses a\n\t// scheme outside the configured allowlist (default: http, https).\n\tErrUpstreamSchemeNotAllowed = errors.New(\"proxy: upstream scheme is not allowed\")\n\n\t// ErrUpstreamHostInvalid is returned when the proxied URL is missing a\n\t// host or cannot be parsed.\n\tErrUpstreamHostInvalid = errors.New(\"proxy: upstream host is empty or invalid\")\n\n\t// ErrUpstreamHostBlocked is returned when the proxied URL resolves to\n\t// an address inside a blocked range (loopback, RFC 1918 private,\n\t// link-local, multicast, unspecified, or CGNAT) and AllowPrivateIPs\n\t// is false.\n\tErrUpstreamHostBlocked = errors.New(\"proxy: upstream host resolves to a blocked address\")\n\n\t// ErrRedirectDowngrade is returned when DoRedirects encounters a\n\t// redirect from an HTTPS upstream to a plaintext HTTP target and\n\t// AllowHTTPSDowngrade is false.\n\tErrRedirectDowngrade = errors.New(\"proxy: HTTPS to HTTP redirect blocked\")\n)\n\n// SecurityPolicy controls runtime security restrictions applied to the\n// proxy.Do, proxy.Forward, proxy.DoRedirects, proxy.DoTimeout, and\n// proxy.DoDeadline runtime helpers as well as Balancer instances that\n// do not supply their own policy via Config.SecurityPolicy.\ntype SecurityPolicy struct {\n\t// AllowedSchemes restricts the URL schemes accepted as upstream\n\t// targets. Empty defaults to []string{schemeHTTP, schemeHTTPS}.\n\tAllowedSchemes []string\n\n\t// AllowPrivateIPs allows upstream hosts to resolve to loopback,\n\t// private (RFC 1918), link-local, multicast, unspecified, or CGNAT","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/proxy/security.go#L43-L79","documentation":"Default SSRF protection: the proxy resolves the upstream host and blocks any address in loopback, RFC 1918 private, link-local, multicast, unspecified, or CGNAT (100.64/10) ranges when AllowPrivateIPs is false (the default). This stops attackers from using the proxy as a pivot into internal services (169.254.169.254 metadata, internal admin panels, etc.).","triggerScenarios":"Proxying to localhost, 127.0.0.1, 10.x, 172.16-31.x, 192.168.x, 169.254.x, 100.64/10, or any hostname whose DNS resolves into those ranges, with AllowPrivateIPs=false. Triggered by proxy.Do/Forward/DoTimeout/DoDeadline and by redirect-following helpers.","commonSituations":"Local development hitting localhost through the proxy; service-to-service calls to internal IPs; CI runners resolving public-looking hostnames to private ranges; SSRF payloads pointing at cloud metadata endpoints.","solutions":["Use a publicly routable upstream host/IP for the proxy target.","If internal traffic is intended and the network is trusted, set SecurityPolicy.AllowPrivateIPs=true (document the trust decision in the project's exposure posture).","Pre-resolve the target and validate it against an explicit allowlist of internal services instead of blanket-allowing all private IPs.","For redirect chains, remember each hop is re-checked; pin allowed redirect hosts."],"exampleFix":"// before\ncfg := proxy.Config{ /* AllowPrivateIPs defaults to false */ }\n\n// after (trusted internal mesh only)\ncfg := proxy.Config{\n    SecurityPolicy: &proxy.SecurityPolicy{AllowPrivateIPs: true},\n}","handlingStrategy":"validation","validationCode":"ips, err := net.LookupIP(host)\nif err != nil { return fiber.NewError(fiber.StatusBadRequest, \"cannot resolve host\") }\nfor _, ip := range ips {\n    if isPrivate(ip) && !policy.AllowPrivateIPs {\n        return fiber.NewError(fiber.StatusForbidden, \"internal target blocked\")\n    }\n}","typeGuard":"func isPrivate(ip net.IP) bool {\n    for _, cidr := range []string{\"127.0.0.0/8\",\"10.0.0.0/8\",\"172.16.0.0/12\",\"192.168.0.0/16\",\"169.254.0.0/16\",\"100.64.0.0/10\",\"0.0.0.0/8\"} {\n        if _, n, _ := net.ParseCIDR(cidr); n.Contains(ip) { return true }\n    }\n    return ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsMulticast() || ip.IsUnspecified()\n}","tryCatchPattern":null,"preventionTips":["Allowlist specific internal services rather than blanket-enabling AllowPrivateIPs.","Re-resolve on every hop when following redirects.","Record the trust decision (loopback|lan|public) in the project's exposure docs."],"tags":["proxy","security","ssrf","network","private-ip"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}