gofiber/fiber · error · ErrUpstreamHostBlocked
%w: %s lookup failed: %w
Error message
%w: %s lookup failed: %w
What it means
validateHostForSSRF performs a bounded DNS lookup (dnsLookupTimeout = 5s) when the host is not a literal IP. If LookupIPAddr fails — network/DNS error, NXDOMAIN with an error response, resolver unreachable, or the 5s timeout elapses — the error is wrapped with ErrUpstreamHostBlocked and the underlying resolver error preserved.
Source
Thrown at middleware/proxy/security.go:402
func validateHostForSSRF(host string) error {
if host == "" {
return ErrUpstreamHostInvalid
}
// strip brackets from IPv6 literals (url.Hostname already does this
// in most cases, but keep the guard for defensive callers).
host = trimBrackets(host)
if ip := net.ParseIP(host); ip != nil {
if isBlockedIP(ip) {
return fmt.Errorf("%w: %s", ErrUpstreamHostBlocked, ip)
}
return nil
}
// Bound the lookup so a slow resolver cannot stall the caller.
ctx, cancel := context.WithTimeout(context.Background(), dnsLookupTimeout)
defer cancel()
addrs, err := dnsResolver.Load().LookupIPAddr(ctx, host)
if err != nil {
return fmt.Errorf("%w: %s lookup failed: %w", ErrUpstreamHostBlocked, host, err)
}
if len(addrs) == 0 {
return fmt.Errorf("%w: %s has no addresses", ErrUpstreamHostBlocked, host)
}
for _, addr := range addrs {
if isBlockedIP(addr.IP) {
return fmt.Errorf("%w: %s -> %s", ErrUpstreamHostBlocked, host, addr.IP)
}
}
return nil
}
// newSSRFDialer returns a fasthttp DialFunc that resolves the target host
// (with a bounded timeout), rejects the connection if any resolved
// address falls in a blocked range, and then dials a validated address.
// Performing the check at dial time — rather than only up front — defeats
// DNS-rebinding attacks (the check/use gap) where a resolver returns a
// public address during validation and a private one at connect time. ItView on GitHub (pinned to a105acad6c)
Solutions
- Verify the hostname resolves from the app host: dig +short hostname, nslookup hostname.
- Confirm /etc/resolv.conf or container DNS policy points at a resolver that knows the zone (e.g. cluster DNS for in-cluster services).
- Retry the request — transient resolver failures are common and the limiter/gateway layer can re-attempt validation.
- If the hostname is internal, ensure the resolver reachable by the Go net package is the internal one (net.DefaultResolver).
- For a deliberately unreachable target the operator accepts, wrap the call and treat ErrUpstreamHostBlocked as a 502 to the client.
Example fix
// before: in-cluster service not resolvable from app netns proxy.Do(ctx, "http://my-svc.cluster.local") // after: correct resolver / dnsPolicy // k8s: dnsPolicy: ClusterFirst; ensure /etc/resolv.conf has the cluster DNS
Defensive patterns
Strategy: retry
Validate before calling
// Pre-resolve to give an early, clear error.
if _, err := net.LookupHost(host); err != nil {
return fmt.Errorf("upstream %q not resolvable: %w", host, err)
} Try / catch
if err := proxy.Do(c); err != nil {
if errors.Is(err, proxy.ErrUpstreamHostBlocked) && isDNSError(err) { return c.Status(502).SendString("upstream DNS failure") }
} Prevention
- Use a highly available resolver.
- Confirm /etc/resolv.conf and container dnsPolicy are correct.
- Retry transient resolver failures at the gateway layer.
- Monitor resolver error rate.
When it happens
Trigger: Proxy target hostname cannot be resolved at validation time: NXDOMAIN, DNS server down, SERVFAIL, resolver timeout (>5s), hoster DNS rate-limiting, or IPv6-only resolver with no AAAA and a buggy return code.
Common situations: Transient DNS outage at deploy time; recently created hostname not yet propagated; private DNS zone only resolvable inside a VPC that the app host left; resolver config (/etc/resolv.conf) missing or pointing at a stale server.
Related errors
- %w: %s has no addresses
- ErrUpstreamHostBlocked
- proxy: upstream scheme is not allowed
- failed to resolve TCP address after adding port: %w
- %w: %q
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/152f1f3c17641545.
Report an issue: GitHub.