Tencent/WeKnora · error
SSRF validation failed: %s
Error message
SSRF validation failed: %s
What it means
ValidateURLForSSRF delegates to isSSRFSafeURL for the deep checks (private/link-local IP literals, DNS resolving to internal addresses, localhost, metadata endpoints, etc.). When isSSRFSafeURL reports the URL is unsafe, the reason string is surfaced as 'SSRF validation failed: %s'. This is the catch-all SSRF rejection — the specific reason (e.g. 'resolves to private IP', 'loopback address') is embedded in the message.
Source
Thrown at internal/utils/security.go:1215
if hostname == "" {
return fmt.Errorf("URL has no hostname")
}
// A whitelist relaxes host/IP restrictions only. It must never turn other
// schemes (file://, gopher://, etc.) into valid outbound request targets.
scheme := strings.ToLower(parsed.Scheme)
if scheme != "http" && scheme != "https" {
return fmt.Errorf("invalid scheme: %s (only http/https allowed)", scheme)
}
// If the host is whitelisted, skip the heavy checks.
if IsSSRFWhitelisted(hostname) {
return nil
}
// Delegate to the full SSRF validation (uses the normalised URL).
if safe, reason := isSSRFSafeURL(normalized); !safe {
return fmt.Errorf("SSRF validation failed: %s", reason)
}
return nil
}
// IsSystemProxy 判断是否为系统代理
func IsSystemProxy(host string) bool {
proxyCfg := httpproxy.FromEnvironment()
for _, proxyUrl := range []string{
proxyCfg.HTTPProxy,
proxyCfg.HTTPSProxy,
} {
if proxyUrl == "" {
continue
}
if parse, err := url.Parse(proxyUrl); err == nil {
if parse.Host == host {
return true
}View on GitHub (pinned to 988cbb0330)
Solutions
- Read the embedded reason in the message to see which check fired (loopback, private range, metadata IP)
- Add the host or its CIDR to the SSRF whitelist config (ValidateSSRFWhitelistEntries-managed list) if the target is legitimately required — whitelisting skips the heavy checks
- Use the public hostname instead of a raw internal IP so DNS-based policy can evaluate it correctly
- For local development of MinIO/OBS mocks, whitelist 'localhost' explicitly in the dev environment config
- If it is an SSRF attempt, block the request and log the source
Example fix
// before
client, err := newMinioClient("http://127.0.0.1:9000", ...) // blocked: loopback
// after
// dev config: add localhost to whitelist
SSRF_WHITELIST=localhost,127.0.0.0/8
client, err := newMinioClient("http://127.0.0.1:9000", ...) Defensive patterns
Strategy: try-catch
Validate before calling
n := endpoint
if !strings.Contains(n, "://") { n = "https://" + n }
u, _ := url.Parse(n)
ips, err := net.LookupIP(u.Hostname())
if err == nil {
for _, ip := range ips {
if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() {
log.Printf("endpoint %s resolves to internal IP %s; whitelist it or change target", u.Hostname(), ip)
}
}
} Type guard
func isPublicEndpoint(raw string) bool {
if !strings.Contains(raw, "://") { raw = "https://" + raw }
u, err := url.Parse(raw)
if err != nil { return false }
ips, err := net.LookupIP(u.Hostname())
if err != nil || len(ips) == 0 { return false }
for _, ip := range ips {
if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() { return false }
}
return true
} Try / catch
if err := ValidateURLForSSRF(target); err != nil {
var ssrfErr = err
log.Printf("SSRF block for %q: %v", target, ssrfErr) // reason is embedded in the message
return fmt.Errorf("outbound request to %q blocked: %w", target, err)
} Prevention
- Whitelist legitimate internal hosts (e.g. localhost for local MinIO) via the SSRF whitelist config
- Use public hostnames rather than raw internal IPs where policy allows DNS evaluation
- Never pass user-supplied URLs straight into storage client constructors
- Read the embedded reason string to identify which check (loopback/private/metadata) fired
When it happens
Trigger: The normalized URL passes scheme/hostname checks and is not whitelisted, but isSSRFSafeURL flags it: hostname is localhost/127.0.0.1, resolves to RFC1918 or link-local space, points at the cloud metadata IP (169.254.169.254), or resolves via DNS to an internal address. Called from any storage client constructor or CheckObsConnectivity.
Common situations: Misconfigured endpoints pointing at internal infrastructure from an environment where that is disallowed; tests using 127.0.0.1 against a local MinIO without adding it to the SSRF whitelist; SSRF probes where a user-supplied URL targets internal services.
Related errors
- URL rejected: %w
- base_url SSRF validation failed: %w
- URL rejected for security reasons: %v
- docreader address failed SSRF validation: %w
- blocked by SSRF policy: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/d940dc49dba9cf43.
Report an issue: GitHub.