{"record":{"id":"e969678e57edf3b5","repo":"Tencent/WeKnora","slug":"redirect-blocked-target-url-failed-ssrf-validatio","errorCode":null,"errorMessage":"redirect blocked: target URL failed SSRF validation","messagePattern":"redirect blocked: target URL failed SSRF validation","errorType":"http","errorClass":"ErrSSRFRedirectBlocked","httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":668,"sourceCode":"type SSRFSafeHTTPClientConfig struct {\n\tTimeout            time.Duration\n\tMaxRedirects       int\n\tDisableKeepAlives  bool\n\tDisableCompression bool\n}\n\n// DefaultSSRFSafeHTTPClientConfig returns the default configuration\nfunc DefaultSSRFSafeHTTPClientConfig() SSRFSafeHTTPClientConfig {\n\treturn SSRFSafeHTTPClientConfig{\n\t\tTimeout:            30 * time.Second,\n\t\tMaxRedirects:       10,\n\t\tDisableKeepAlives:  false,\n\t\tDisableCompression: false,\n\t}\n}\n\n// ErrSSRFRedirectBlocked is returned when a redirect target is blocked due to SSRF protection\nvar ErrSSRFRedirectBlocked = fmt.Errorf(\"redirect blocked: target URL failed SSRF validation\")\n\n// sameHTTPOrigin reports whether two URLs share scheme and host (port-aware).\nfunc sameHTTPOrigin(a, b *url.URL) bool {\n\tif a == nil || b == nil {\n\t\treturn false\n\t}\n\treturn strings.EqualFold(a.Scheme, b.Scheme) && strings.EqualFold(a.Host, b.Host)\n}\n\n// stripRedirectSensitiveHeaders removes credentials that must not follow a\n// cross-host redirect (Go only strips Authorization/Cookie by default).\nfunc stripRedirectSensitiveHeaders(req *http.Request) {\n\treq.Header.Del(\"Authorization\")\n\treq.Header.Del(\"Cookie\")\n\treq.Header.Del(\"X-Auth-Token\")\n\treq.Header.Del(\"X-Api-Key\")\n\treq.Header.Del(\"Api-Key\")\n}","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L650-L686","documentation":"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).","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nresp, err := client.Do(req)\nif err != nil { return err } // generic handling\n// after\nresp, err := client.Do(req)\nif errors.Is(err, secutils.ErrSSRFRedirectBlocked) {\n    return fmt.Errorf(\"upstream redirected to a blocked internal target\")\n}","handlingStrategy":"try-catch","validationCode":"u, err := url.Parse(finalURL)\nif err != nil { return err }\nif isPrivateIP(u.Hostname()) { return fmt.Errorf(\"target %s is internal; refusing\", finalURL) }","typeGuard":"func isSSRFRedirectBlocked(err error) bool { return errors.Is(err, secutils.ErrSSRFRedirectBlocked) }","tryCatchPattern":"resp, err := client.Do(req)\nif errors.Is(err, secutils.ErrSSRFRedirectBlocked) {\n    // treat as terminal: do not retry, inspect redirect chain\n    return fmt.Errorf(\"blocked redirect: %w\", err)\n}","preventionTips":["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."],"tags":["security","ssrf","http","redirect"],"backgroundTag":"ssrf-redirect-blocked","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}