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

  1. Check errors.Is(err, secutils.ErrSSRFRedirectBlocked) and treat the redirect as final — do not retry.
  2. Verify the upstream service: it should not redirect to internal addresses; fix the redirect chain.
  3. If the redirect target is legitimate and internal by design, add it to the SSRF whitelist (IsSSRFWhitelisted) after security review.
  4. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/e969678e57edf3b5. Report an issue: GitHub.