Tencent/WeKnora · error · ErrSSRFRedirectBlocked
%w: %w
Error message
%w: %w
What it means
When a redirect target is not on the SSRF whitelist, it is run through validateURLForSSRFForOutbound; if that fails (private IP, blocked host, etc.) the policy returns ErrSSRFRedirectBlocked wrapped with the underlying validation error ('%w: %w'), so both the sentinel and the cause are matchable via errors.Is.
Source
Thrown at internal/utils/security.go:728
// 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.
type SSRFValidatingRoundTripper struct {
Base http.RoundTripper
}
func (t *SSRFValidatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if req == nil || req.URL == nil {
return nil, fmt.Errorf("outbound request blocked: request URL is required")View on GitHub (pinned to 988cbb0330)
Solutions
- Handle with errors.Is(err, secutils.ErrSSRFRedirectBlocked); log the wrapped cause for the specific reason.
- Fix the upstream so it does not redirect to private/internal addresses.
- If the target host is legitimately required, add it to the SSRF whitelist after security review (whitelisted hosts bypass outbound validation).
- Resolve the public hostname instead of an internal one on the redirecting service.
Example fix
// before
resp, err := client.Do(req)
return err
// after
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
return fmt.Errorf("redirect target failed SSRF validation: %v", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-resolve and check the redirect target
ips, _ := net.LookupHost(host)
for _, ip := range ips { if isPrivate(ip) { return fmt.Errorf("redirect target %s is private", ip) } } Type guard
func isRedirectSSRFBlocked(err error) bool { return errors.Is(err, secutils.ErrSSRFRedirectBlocked) } Try / catch
if errors.Is(err, secutils.ErrSSRFRedirectBlocked) {
// wrapped cause explains why: private IP, blocked host, etc.
return fmt.Errorf("redirect failed SSRF policy: %w", err)
} Prevention
- Match the sentinel with errors.Is and log the wrapped cause.
- Avoid following redirects from untrusted endpoints.
- Whitelist only hosts that are legitimately required.
- Watch logs for repeated blocks — may indicate probing.
When it happens
Trigger: Following a redirect whose Location URL fails validateURLForSSRFForOutbound — e.g. target resolves to loopback, RFC1918, or link-local addresses — while using newSSRFCheckRedirect.
Common situations: Open redirects on third-party APIs pointing at internal hosts, DNS rebinding attempts, or staging services that redirect to internal-only backends.
Related errors
- redirect blocked: target URL failed SSRF validation
- %w: invalid scheme %s
- 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/2f3d1c3b883e43a1.
Report an issue: GitHub.