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

  1. Read the embedded reason in the message to see which check fired (loopback, private range, metadata IP)
  2. 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
  3. Use the public hostname instead of a raw internal IP so DNS-based policy can evaluate it correctly
  4. For local development of MinIO/OBS mocks, whitelist 'localhost' explicitly in the dev environment config
  5. 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

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


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