gofiber/fiber · error
ErrUpstreamSchemeNotAllowed
ErrUpstreamSchemeNotAllowed
Error message
%w: %q
What it means
Returned by parseUpstreamScheme when the upstream URL's scheme is not in the configured AllowedSchemes allowlist (default: http, https). Wraps the ErrUpstreamSchemeNotAllowed sentinel.
Source
Thrown at middleware/proxy/security.go:331
return u, nil
}
if err := validateHostForSSRF(u.Hostname()); err != nil {
return nil, err
}
return u, nil
}
// parseUpstreamScheme parses raw and enforces the scheme allowlist and
// host presence without performing any DNS resolution. url.Parse can
// leave Host set while Hostname() is empty (e.g. "http://:8080"), so the
// presence check uses Hostname.
func parseUpstreamScheme(raw string, policy SecurityPolicy) (*url.URL, error) {
u, err := parseUpstream(raw)
if err != nil {
return nil, err
}
if !schemeAllowed(u.Scheme, policy.AllowedSchemes) {
return nil, fmt.Errorf("%w: %q", ErrUpstreamSchemeNotAllowed, u.Scheme)
}
if u.Hostname() == "" {
return nil, ErrUpstreamHostInvalid
}
return u, nil
}
// validateUpstreamForBalancer validates a statically configured Balancer
// upstream. It enforces the scheme allowlist and rejects IP-literal hosts
// in blocked ranges, but defers hostname resolution to the SSRF-guarded
// dialer (see newSSRFDialer). Deferring DNS keeps a transient resolver
// failure at startup from panicking the application (e.g. crash loops in
// container orchestrators) and re-checks the resolved IP on every dial,
// which also defeats DNS-rebinding.
func validateUpstreamForBalancer(raw string, policy SecurityPolicy) (*url.URL, error) {
u, err := parseUpstreamScheme(raw, policy)
if err != nil {
return nil, errView on GitHub (pinned to 9a4c7e57fe)
Solutions
- Ensure the upstream uses http or https.
- If a different scheme is genuinely required, explicitly add it via SecurityPolicy.AllowedSchemes (review the security implications first).
- Reject user-controlled upstream input that specifies a scheme other than http/https.
Example fix
// before: user-supplied upstream may use file://
proxy.Do(ctx, userInput)
// after: force http(s) only
u, _ := url.Parse(userInput)
if u.Scheme != "http" && u.Scheme != "https" {
return fiber.NewError(fiber.StatusBadRequest, "scheme not allowed")
}
proxy.Do(ctx, u.String()) Defensive patterns
Strategy: validation
Validate before calling
// Reject any scheme other than http/https before proxying.
func allowedScheme(raw string) error {
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return err
}
if u.Scheme != "http" && u.Scheme != "https" {
return fmt.Errorf("scheme %q not permitted", u.Scheme)
}
return nil
} Try / catch
err := proxy.Do(c, upstream)
if errors.Is(err, proxy.ErrUpstreamSchemeNotAllowed) {
return fiber.NewError(fiber.StatusBadRequest, "upstream scheme not allowed")
} Prevention
- Maintain an allowlist of permitted upstream hosts, not just schemes.
- Never feed user-controlled URLs directly to the proxy.
- Review any decision to widen AllowedSchemes for SSRF impact.
When it happens
Trigger: Proxied target uses a scheme like file://, ftp://, gopher://, or an empty scheme, none of which are in the allowlist enforced at security.go:330.
Common situations: Attacker-controlled upstream allowing file:// to read local files; misconfigured upstream with a wrong scheme; intentional use of a non-http scheme that must be explicitly allowed via SecurityPolicy.AllowedSchemes.
Related errors
- proxy: upstream scheme is not allowed
- proxy: upstream host resolves to a blocked address
- ErrUpstreamHostBlocked
- proxy: upstream host is empty or invalid
- proxy: HTTPS to HTTP redirect blocked
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/8457f7c10b001c44.json.
Report an issue: GitHub.