Tencent/WeKnora · error

outbound request blocked by SSRF policy: %w

Error message

outbound request blocked by SSRF policy: %w

What it means

The request URL failed the library's SSRF policy check performed by validateURLForSSRFForOutbound before the request is handed to the base transport. The library blocks outbound requests to disallowed destinations (private/loopback/link-local IPs, restricted hosts, restricted ports, non-safe schemes) to prevent server-side request forgery. The wrapped cause (%w) explains exactly which rule was violated.

Source

Thrown at internal/utils/security.go:752

// 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")
	}
	if t == nil || t.Base == nil {
		return nil, fmt.Errorf("outbound request blocked: base transport is required")
	}
	if err := validateURLForSSRFForOutbound(req.URL.String()); err != nil {
		return nil, fmt.Errorf("outbound request blocked by SSRF policy: %w", err)
	}
	return t.Base.RoundTrip(req)
}

// NewSSRFSafeHTTPClientWithTransport wraps a caller-supplied transport in an
// *http.Client carrying the given timeout and the SSRF-aware redirect policy.
// Pass a transport from NewSSRFSafeTransport (optionally shared across clients)
// to reuse a single connection pool while keeping per-client timeouts.
func NewSSRFSafeHTTPClientWithTransport(
	config SSRFSafeHTTPClientConfig, transport http.RoundTripper,
) *http.Client {
	if transport == nil {
		transport = NewSSRFSafeTransport(config)
	}
	return &http.Client{
		Timeout:       config.Timeout,
		Transport:     &SSRFValidatingRoundTripper{Base: transport},
		CheckRedirect: newSSRFCheckRedirect(config.MaxRedirects),

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped error (errors.Unwrap / %v of the chain) to see which SSRF rule fired, then change the target URL to a public, allowed host.
  2. If the destination is legitimately internal, add it to the SSRF whitelist mechanism provided by the library (whitelisted hosts bypass the checks) rather than disabling validation.
  3. For tests, point the request at the approved test host or inject a whitelist entry instead of using 127.0.0.1.
  4. Validate the URL yourself with ValidateURLForSSRF before building the request to get an earlier, clearer failure.

Example fix

// before
req, _ := http.NewRequest("GET", "http://169.254.169.254/latest/meta-data/", nil)
resp, err := client.Do(req) // blocked by SSRF policy

// after
if err := utils.ValidateURLForSSRF("https://api.example.com/v1/info"); err != nil { /* handle */ }
req, _ := http.NewRequest("GET", "https://api.example.com/v1/info", nil)
resp, err := client.Do(req)
Defensive patterns

Strategy: validation

Validate before calling

if err := utils.ValidateURLForSSRF(targetURL); err != nil {
    return fmt.Errorf("refusing to fetch %s: %w", targetURL, err)
}
req, _ := http.NewRequest("GET", targetURL, nil)

Try / catch

resp, err := client.Do(req)
if err != nil {
    var blocked *fmt.Errorf
    if strings.Contains(err.Error(), "blocked by SSRF policy") {
        // log the policy violation, do not retry — it will keep failing
        return nil, fmt.Errorf("target rejected by SSRF policy: %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: RoundTrip (e.g. via an http.Client configured with SSRFValidatingRoundTripper) invoked with a request whose URL fails validateURLForSSRFForOutbound: pointing at 127.0.0.1/localhost, private RFC1918 ranges, metadata endpoints (169.254.169.254), file/non-http schemes, restricted ports, or a hostname that resolves to a blocked IP. TestSSRFValidatingRoundTripperUsesOutboundCache reaches this path whenever the URL is not policy-compliant.

Common situations: Calling internal microservice endpoints like http://localhost:8080 from behind the SSRF-safe client; fetching user-supplied URLs that target internal addresses; cloud-metadata lookups from inside the guarded code path; tests pointing at a local httptest server.

Related errors


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