{"record":{"id":"332fedb494d62074","repo":"gofiber/fiber","slug":"errupstreamschemenotallowed","errorCode":"ErrUpstreamSchemeNotAllowed","errorMessage":"proxy: upstream scheme is not allowed","messagePattern":"proxy: upstream scheme is not allowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/proxy/proxy.go","lineNumber":41,"sourceCode":"// Balancer creates a load balancer among multiple upstream servers\nfunc Balancer(config ...Config) fiber.Handler {\n\t// Set default config\n\tcfg := configDefault(config...)\n\tpolicy := resolvePolicy(cfg.SecurityPolicy)\n\n\t// Load balanced client\n\tlbc := &fasthttp.LBClient{}\n\t// Note that Servers, Timeout, WriteBufferSize, ReadBufferSize and TLSConfig\n\t// will not be used if the client are set.\n\tif cfg.Client == nil {\n\t\t// Set timeout\n\t\tlbc.Timeout = cfg.Timeout\n\t\t// Validate each upstream against the configured policy and build\n\t\t// a HostClient per server.\n\t\tfor _, server := range cfg.Servers {\n\t\t\tu, err := validateUpstreamForBalancer(server, policy)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\n\t\t\tclient := &fasthttp.HostClient{\n\t\t\t\tNoDefaultUserAgentHeader: true,\n\t\t\t\tDisablePathNormalizing:   true,\n\t\t\t\tAddr:                     u.Host,\n\t\t\t\tMaxConns:                 cfg.MaxConnsPerHost,\n\n\t\t\t\tReadBufferSize:  cfg.ReadBufferSize,\n\t\t\t\tWriteBufferSize: cfg.WriteBufferSize,\n\n\t\t\t\tTLSConfig: secureTLSConfig(cfg.TLSConfig),\n\n\t\t\t\tDialDualStack: cfg.DialDualStack,\n\n\t\t\t\tMaxResponseBodySize: cfg.MaxResponseBodySize,\n\t\t\t}\n\t\t\tif u.Scheme == schemeHTTPS {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/proxy/proxy.go#L23-L59","documentation":"proxy.Balancer validates each entry in Config.Servers via validateUpstreamForBalancer, which calls parseUpstreamScheme and enforces a scheme allowlist. If the URL's scheme is not allowed (default allowlist is http/https), it returns ErrUpstreamSchemeNotAllowed wrapped as fmt.Errorf(\"%w: %q\", ErrUpstreamSchemeNotAllowed, scheme); Balancer then panics with that error. This is an SSRF-defense measure: non-HTTP schemes (gopher, file, etc.) must never be proxied.","triggerScenarios":"A Servers entry like \"gopher://internal:6379\", \"file:///etc/passwd\", \"ftp://host\", or an entry missing a scheme (which parses with Scheme=\"\" and is rejected). Also triggered by a custom SecurityPolicy whose AllowedSchemes omits the scheme you actually use.","commonSituations":"Pointing the balancer at a non-HTTP backend by mistake; a misconfigured custom SecurityPolicy that narrows AllowedSchemes below what your upstreams need; a server string that lost its scheme during templating (\"upstream:8080\" instead of \"http://upstream:8080\").","solutions":["Use http:// or https:// schemes for all Servers entries.","If you legitimately need another scheme, configure a SecurityPolicy with an AllowedSchemes list that includes it (and review the SSRF implications).","Ensure every server string has an explicit scheme prefix — reconstruct with fmt.Sprintf(\"http://%s\", host) if needed."],"exampleFix":"// before\napp.Use(proxy.Balancer(proxy.Config{\n    Servers: []string{\"gopher://cache:6379\"},\n}))\n\n// after\napp.Use(proxy.Balancer(proxy.Config{\n    Servers: []string{\"http://cache:6379\"},\n}))","handlingStrategy":"validation","validationCode":"var allowedSchemes = map[string]struct{}{\"http\": {}, \"https\": {}}\n\nfunc validateUpstreamSchemes(servers []string) error {\n    for _, s := range servers {\n        u, err := url.Parse(s)\n        if err != nil {\n            return fmt.Errorf(\"bad upstream %q: %w\", s, err)\n        }\n        if _, ok := allowedSchemes[u.Scheme]; !ok {\n            return fmt.Errorf(\"%w: %q\", proxy.ErrUpstreamSchemeNotAllowed, u.Scheme)\n        }\n    }\n    return nil\n}","typeGuard":"func isAllowedUpstreamScheme(scheme string) bool {\n    _, ok := map[string]struct{}{\"http\": {}, \"https\": {}}[strings.ToLower(scheme)]\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Restrict upstream schemes to http/https unless a reviewed SecurityPolicy explicitly widens them.","Always prefix server strings with an explicit scheme.","Validate the scheme allowlist at config load to surface SSRF-risky URLs before startup."],"tags":["proxy","ssrf","security","scheme","config","startup-panic"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}