{"id":"f4b72a331b69c84d","repo":"gofiber/fiber","slug":"proxy-upstream-scheme-is-not-allowed","errorCode":null,"errorMessage":"proxy: upstream scheme is not allowed","messagePattern":"proxy: upstream scheme is not allowed","errorType":"http","errorClass":"ErrUpstreamSchemeNotAllowed","httpStatus":null,"severity":"critical","filePath":"middleware/proxy/security.go","lineNumber":50,"sourceCode":"// defaultAllowedSchemes is the internal, read-only allowlist used as the\n// fallback inside schemeAllowed when a policy carries no AllowedSchemes.\n// It is never handed out by reference: DefaultSecurityPolicy() and\n// normalizePolicy() copy it before it can reach the exported\n// 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","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/proxy/security.go#L32-L68","documentation":"Returned by proxy.parseUpstreamScheme (security.go:50, 331) when the upstream URL's scheme is not in the configured AllowedSchemes allowlist (default: 'http' and 'https'). The proxy enforces a scheme allowlist to prevent SSRF via exotic schemes (gopher://, file://, etc.). It fires during validateUpstream, which runs at request time for Do/Forward and at construction time (panic) for DomainForward/BalancerForward.","triggerScenarios":"Configuring an upstream with a scheme like 'gopher://', 'ftp://', 'file://', or 'ws://' when AllowedSchemes only permits http/https. For DomainForward/BalancerForward this panics at startup (security_test.go:843); for Do/Forward it returns the error per-request. An empty scheme also fails (schemeAllowed returns false for \"\").","commonSituations":"Typing 'ftp://' or omitting the scheme (which parseUpstream defaults to http://, so this is fine, but a truly empty scheme fails); intentionally proxying to a non-http service; misconfigured SecurityPolicy.AllowedSchemes that drops http/https; copied upstream URLs that include unexpected schemes.","solutions":["Use only 'http://' or 'https://' upstream URLs unless you have explicitly added other schemes to SecurityPolicy.AllowedSchemes.","If you legitimately need another scheme, add it to SecurityPolicy.AllowedSchemes in your proxy config (review the SSRF implications first).","For DomainForward/BalancerForward, fix the scheme before deployment since it panics at startup."],"exampleFix":"// before — startup panic\nproxy.BalancerForward([]string{\"gopher://internal:7070\"})\n// after\nproxy.BalancerForward([]string{\"http://internal:7070\"})\n\n// or extend the allowlist deliberately\nproxy.SetSecurityPolicy(proxy.SecurityPolicy{AllowedSchemes: []string{\"http\", \"https\", \"ws\"}})","handlingStrategy":"validation","validationCode":"// Validate the upstream scheme before configuring\nu, err := url.Parse(upstream)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n    log.Fatalf(\"upstream %q must use http or https\", upstream)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict upstream URLs to http/https unless you deliberately extend AllowedSchemes.","For DomainForward/BalancerForward, test startup locally to catch scheme panics before deploy.","Review SecurityPolicy.AllowedSchemes changes with SSRF risk in mind."],"tags":["proxy","security","ssrf","configuration","scheme"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}