{"id":"e3b7c5cbf12288f2","repo":"gofiber/fiber","slug":"proxy-upstream-host-is-empty-or-invalid","errorCode":null,"errorMessage":"proxy: upstream host is empty or invalid","messagePattern":"proxy: upstream host is empty or invalid","errorType":"http","errorClass":"ErrUpstreamHostInvalid","httpStatus":null,"severity":"critical","filePath":"middleware/proxy/security.go","lineNumber":54,"sourceCode":"// SecurityPolicy.AllowedSchemes field, so nothing outside this file can\n// mutate the backing array.\nvar defaultAllowedSchemes = []string{schemeHTTP, schemeHTTPS}\n\n// httpsSchemeBytes is the byte form of \"https\" used by redirect\n// downgrade checks. Stored once so the resolveRedirect hot path doesn't\n// 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 {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/proxy/security.go#L36-L72","documentation":"Returned by proxy.parseUpstream/parseUpstreamScheme (security.go:54, 290, 334) and validateHostForSSRF when the upstream URL has an empty host (e.g. 'http://:8080' where Hostname() is empty) or the raw upstream string is empty/whitespace. The proxy requires a concrete hostname to dial; an empty host is both a misconfiguration and an SSRF risk. Fires per-request for Do/Forward and as a startup panic for DomainForward/BalancerForward.","triggerScenarios":"Passing an empty string or whitespace to proxy.Do/Forward; configuring an upstream like 'http://:8080' (port but no host); a URL like 'http:///path' (empty host); or a dynamically-built upstream where the host variable is unset. validateHostForSSRF (security.go:390) also returns it when the resolved host is empty.","commonSituations":"Environment variable for the upstream host is unset (empty string); templated upstream URL with a missing variable; copy-paste error dropping the hostname; upstream built from request input where the host part is absent; IPv6 URL missing brackets.","solutions":["Ensure the upstream URL includes a non-empty hostname or IP (e.g. 'http://backend:8080').","Validate the upstream string is non-empty before passing it to proxy functions.","For env-driven upstreams, fail fast at startup if the env var is empty rather than per-request."],"exampleFix":"// before\nupstream := os.Getenv(\"UPSTREAM_URL\") // may be empty\nproxy.Do(c, upstream)\n// after\nupstream := os.Getenv(\"UPSTREAM_URL\")\nif upstream == \"\" {\n  return c.SendStatus(fiber.StatusBadGateway)\n}\nproxy.Do(c, upstream)","handlingStrategy":"validation","validationCode":"// Validate upstream host is non-empty before proxying\nu, err := url.Parse(upstream)\nif err != nil || u.Hostname() == \"\" {\n    return c.Status(fiber.StatusBadGateway).SendString(\"invalid upstream\")\n}\nreturn proxy.Do(c, upstream)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fail fast at startup if env-driven upstream URLs are empty.","Validate dynamically-built upstreams include a host component.","Log the upstream string on proxy errors to catch empty-host bugs."],"tags":["proxy","configuration","ssrf","validation","url"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}