gofiber/fiber · error

ErrUpstreamHostBlocked

ErrUpstreamHostBlocked

Error message

proxy: upstream host resolves to a blocked address

What it means

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.).

Solutions

  1. Use a publicly routable upstream host/IP for the proxy target.
  2. If internal traffic is intended and the network is trusted, set SecurityPolicy.AllowPrivateIPs=true (document the trust decision in the project's exposure posture).
  3. Pre-resolve the target and validate it against an explicit allowlist of internal services instead of blanket-allowing all private IPs.
  4. For redirect chains, remember each hop is re-checked; pin allowed redirect hosts.

Example fix

// before
cfg := proxy.Config{ /* AllowPrivateIPs defaults to false */ }

// after (trusted internal mesh only)
cfg := proxy.Config{
    SecurityPolicy: &proxy.SecurityPolicy{AllowPrivateIPs: true},
}
Defensive patterns

Strategy: validation

Validate before calling

ips, err := net.LookupIP(host)
if err != nil { return fiber.NewError(fiber.StatusBadRequest, "cannot resolve host") }
for _, ip := range ips {
    if isPrivate(ip) && !policy.AllowPrivateIPs {
        return fiber.NewError(fiber.StatusForbidden, "internal target blocked")
    }
}

Type guard

func isPrivate(ip net.IP) bool {
    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"} {
        if _, n, _ := net.ParseCIDR(cidr); n.Contains(ip) { return true }
    }
    return ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsMulticast() || ip.IsUnspecified()
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/cee29237fc14327e. Report an issue: GitHub.

Appendix: source

Thrown at middleware/proxy/security.go:61

// allocate []byte("https") on every hop.
var httpsSchemeBytes = []byte(schemeHTTPS)

// Sentinel errors returned when an upstream target violates the configured
// proxy security policy.
var (
	// ErrUpstreamSchemeNotAllowed is returned when the proxied URL uses a
	// scheme outside the configured allowlist (default: http, https).
	ErrUpstreamSchemeNotAllowed = errors.New("proxy: upstream scheme is not allowed")

	// ErrUpstreamHostInvalid is returned when the proxied URL is missing a
	// host or cannot be parsed.
	ErrUpstreamHostInvalid = errors.New("proxy: upstream host is empty or invalid")

	// ErrUpstreamHostBlocked is returned when the proxied URL resolves to
	// an address inside a blocked range (loopback, RFC 1918 private,
	// link-local, multicast, unspecified, or CGNAT) and AllowPrivateIPs
	// is false.
	ErrUpstreamHostBlocked = errors.New("proxy: upstream host resolves to a blocked address")

	// ErrRedirectDowngrade is returned when DoRedirects encounters a
	// redirect from an HTTPS upstream to a plaintext HTTP target and
	// AllowHTTPSDowngrade is false.
	ErrRedirectDowngrade = errors.New("proxy: HTTPS to HTTP redirect blocked")
)

// SecurityPolicy controls runtime security restrictions applied to the
// proxy.Do, proxy.Forward, proxy.DoRedirects, proxy.DoTimeout, and
// proxy.DoDeadline runtime helpers as well as Balancer instances that
// do not supply their own policy via Config.SecurityPolicy.
type SecurityPolicy struct {
	// AllowedSchemes restricts the URL schemes accepted as upstream
	// targets. Empty defaults to []string{schemeHTTP, schemeHTTPS}.
	AllowedSchemes []string

	// AllowPrivateIPs allows upstream hosts to resolve to loopback,
	// private (RFC 1918), link-local, multicast, unspecified, or CGNAT

View on GitHub (pinned to a105acad6c)