Tencent/WeKnora · error · ErrSSRFRedirectBlocked
%w: invalid scheme %s
Error message
%w: invalid scheme %s
What it means
A redirect target used a URL scheme other than http or https (e.g. file:, gopher:, ftp:). The redirect policy wraps ErrSSRFRedirectBlocked with 'invalid scheme %s' because even whitelisted hosts must use http/https, blocking scheme-based attacks during redirect following.
Source
Thrown at internal/utils/security.go:721
// every redirect target against SSRF protections.
func newSSRFCheckRedirect(maxRedirects int) func(*http.Request, []*http.Request) error {
return func(req *http.Request, via []*http.Request) error {
// Check redirect count
if len(via) >= maxRedirects {
return fmt.Errorf("stopped after %d redirects", maxRedirects)
}
// Strip credentials when the redirect crosses hosts so connector
// tokens (e.g. Yuque X-Auth-Token) cannot leak to a third party.
if len(via) > 0 && !sameHTTPOrigin(via[0].URL, req.URL) {
stripRedirectSensitiveHeaders(req)
}
// Validate the redirect target URL for SSRF (whitelist-aware).
// Even whitelisted hosts must use http/https to prevent scheme-based attacks.
redirectScheme := strings.ToLower(req.URL.Scheme)
if redirectScheme != "http" && redirectScheme != "https" {
return fmt.Errorf("%w: invalid scheme %s", ErrSSRFRedirectBlocked, redirectScheme)
}
redirectHost := req.URL.Hostname()
if redirectHost != "" && IsSSRFWhitelisted(redirectHost) {
return nil
}
if err := validateURLForSSRFForOutbound(req.URL.String()); err != nil {
return fmt.Errorf("%w: %w", ErrSSRFRedirectBlocked, err)
}
return nil
}
}
// SSRFValidatingRoundTripper enforces the URL policy for every outbound
// request, including URLs discovered at runtime by SDKs (for example OAuth
// metadata) that never passed through an application handler. Dial-time checks
// remain necessary to pin DNS answers and cover transports that cannot accept
// this wrapper directly.View on GitHub (pinned to 988cbb0330)
Solutions
- errors.Is(err, secutils.ErrSSRFRedirectBlocked) will match — handle it as a blocked redirect and stop.
- Only follow redirects from trusted servers; never point the client at untrusted endpoints that control Location.
- Ensure the upstream URL you call is https so any redirect it issues stays in-scheme.
- Check the server's Location header construction for a bug producing a bad scheme.
Example fix
// before
resp, err := client.Do(req) // server redirects to file://...
// after
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
log.Printf("refusing redirect: %v", err) // inspect/fix upstream Location scheme
} Defensive patterns
Strategy: try-catch
Validate before calling
if u.Scheme != "http" && u.Scheme != "https" { return fmt.Errorf("unsupported scheme: %s", u.Scheme) } Type guard
func isBlockedRedirectScheme(err error) bool {
return errors.Is(err, secutils.ErrSSRFRedirectBlocked)
} Try / catch
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
log.Printf("redirect rejected (check scheme/Location): %v", err)
return err
} Prevention
- Only call trusted servers that emit http(s) Location headers.
- Start from https URLs so redirects stay in-scheme.
- Never let fully attacker-controlled endpoints drive your redirect chain.
When it happens
Trigger: A server responds with a Location header whose scheme is not http/https while the client follows redirects through newSSRFCheckRedirect.
Common situations: Malicious or buggy servers emitting 'Location: file:///etc/passwd' or custom-scheme redirects; attacker-controlled endpoints attempting to pivot the client away from HTTP.
Related errors
- redirect blocked: target URL failed SSRF validation
- %w: %w
- docreader address failed SSRF validation: %w
- URL rejected by SSRF policy: %w
- invalid scheme: %s (only http/https allowed)
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/a52eecd040e41fd5.
Report an issue: GitHub.