Tencent/WeKnora · error · ErrSSRFRedirectBlocked
redirect blocked: target URL failed SSRF validation
Error message
redirect blocked: target URL failed SSRF validation
What it means
ErrSSRFRedirectBlocked is a sentinel error returned when an HTTP redirect target fails SSRF validation in the library's SSRF-safe redirect policy (newSSRFCheckRedirect). It prevents following redirects to internal/metadata/private-network addresses. Callers should use errors.Is to detect it; the message may be wrapped with extra detail (scheme, validation error).
Source
Thrown at internal/utils/security.go:668
type SSRFSafeHTTPClientConfig struct {
Timeout time.Duration
MaxRedirects int
DisableKeepAlives bool
DisableCompression bool
}
// DefaultSSRFSafeHTTPClientConfig returns the default configuration
func DefaultSSRFSafeHTTPClientConfig() SSRFSafeHTTPClientConfig {
return SSRFSafeHTTPClientConfig{
Timeout: 30 * time.Second,
MaxRedirects: 10,
DisableKeepAlives: false,
DisableCompression: false,
}
}
// ErrSSRFRedirectBlocked is returned when a redirect target is blocked due to SSRF protection
var ErrSSRFRedirectBlocked = fmt.Errorf("redirect blocked: target URL failed SSRF validation")
// sameHTTPOrigin reports whether two URLs share scheme and host (port-aware).
func sameHTTPOrigin(a, b *url.URL) bool {
if a == nil || b == nil {
return false
}
return strings.EqualFold(a.Scheme, b.Scheme) && strings.EqualFold(a.Host, b.Host)
}
// stripRedirectSensitiveHeaders removes credentials that must not follow a
// cross-host redirect (Go only strips Authorization/Cookie by default).
func stripRedirectSensitiveHeaders(req *http.Request) {
req.Header.Del("Authorization")
req.Header.Del("Cookie")
req.Header.Del("X-Auth-Token")
req.Header.Del("X-Api-Key")
req.Header.Del("Api-Key")
}View on GitHub (pinned to 988cbb0330)
Solutions
- Check errors.Is(err, secutils.ErrSSRFRedirectBlocked) and treat the redirect as final — do not retry.
- Verify the upstream service: it should not redirect to internal addresses; fix the redirect chain.
- If the redirect target is legitimate and internal by design, add it to the SSRF whitelist (IsSSRFWhitelisted) after security review.
- Serve content over a single stable host to avoid cross-host redirects.
Example fix
// before
resp, err := client.Do(req)
if err != nil { return err } // generic handling
// after
resp, err := client.Do(req)
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
return fmt.Errorf("upstream redirected to a blocked internal target")
} Defensive patterns
Strategy: try-catch
Validate before calling
u, err := url.Parse(finalURL)
if err != nil { return err }
if isPrivateIP(u.Hostname()) { return fmt.Errorf("target %s is internal; refusing", finalURL) } Type guard
func isSSRFRedirectBlocked(err error) bool { return errors.Is(err, secutils.ErrSSRFRedirectBlocked) } Try / catch
resp, err := client.Do(req)
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
// treat as terminal: do not retry, inspect redirect chain
return fmt.Errorf("blocked redirect: %w", err)
} Prevention
- Always match the sentinel with errors.Is, not string comparison.
- Audit third-party endpoints for open redirects before integrating.
- Keep the SSRF whitelist minimal and reviewed.
- Log blocked redirects for security monitoring.
When it happens
Trigger: Any request through an SSRF-safe client (e.g. newDorisStreamLoadHTTPClient, embed webhook client, OIDC token exchange, Mattermost client) where the server responds with a 3xx whose Location URL resolves to a private/loopback/link-local address, or a wrapped variant with a non-http(s) scheme.
Common situations: A public endpoint behind a misconfigured proxy redirecting to an internal host, an open redirect on a third-party API, or an attacker-controlled server chaining redirects to cloud metadata endpoints (169.254.169.254).
Related errors
- %w: invalid scheme %s
- %w: %w
- docreader address failed SSRF validation: %w
- URL rejected by SSRF policy: %w
- unsafe MinIO endpoint: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/e969678e57edf3b5.
Report an issue: GitHub.