Tencent/WeKnora · error

connection blocked: hostname %s is restricted

Error message

connection blocked: hostname %s is restricted

What it means

SSRFSafeDialContext blocked the connection because the hostname exactly matches an entry in the restrictedHostnames list. Names such as localhost or cloud metadata hostnames are denied at dial time as a second layer of defense behind URL validation. The comparison is case-insensitive (strings.ToLower), so casing tricks do not bypass it.

Source

Thrown at internal/utils/security.go:817

	// ValidateURLForSSRF which skips isSSRFSafeURL for whitelisted hosts.
	// NOTE: This intentionally relaxes DNS-rebinding protection for whitelisted
	// hosts. Admins must ensure whitelisted domains are under their control.
	if IsSystemProxy(addr) || IsSSRFWhitelisted(host) {
		dialer := &net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}
		return dialer.DialContext(ctx, network, addr)
	}
	if restrictedPorts[port] {
		return nil, fmt.Errorf("connection blocked: port %s is restricted", port)
	}

	// Check if the host is a restricted hostname
	hostLower := strings.ToLower(host)
	for _, restricted := range restrictedHostnames {
		if hostLower == restricted {
			return nil, fmt.Errorf("connection blocked: hostname %s is restricted", host)
		}
	}
	for _, suffix := range restrictedHostSuffixes {
		if strings.HasSuffix(hostLower, suffix) {
			return nil, fmt.Errorf("connection blocked: hostname suffix %s is restricted", suffix)
		}
	}

	// Resolve the hostname once, validate every answer, and then dial one of
	// those exact IPs. Dialing the original hostname here would make the
	// standard dialer resolve it a second time, leaving a DNS-rebinding window
	// between validation and connection establishment.
	ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
	if err != nil {
		return nil, fmt.Errorf("DNS resolution failed for %s: %w", host, err)
	}
	if len(ips) == 0 {
		return nil, fmt.Errorf("DNS resolution returned no addresses for %s", host)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Dial the service using a non-restricted hostname or its routable public name instead of the restricted hostname.
  2. For trusted internal endpoints, register the host in the SSRF whitelist so dial-time checks are skipped for it.
  3. In tests, use a whitelisted test host or inject the whitelist before dialing rather than using "localhost".
  4. Confirm the exact restricted list in internal/utils/security.go and rename your service host if it collides accidentally.

Example fix

// before
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "localhost:8080")

// after
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "api.internal.example.com:8080") // or add host to whitelist
Defensive patterns

Strategy: validation

Validate before calling

host, _, _ := net.SplitHostPort(addr)
h := strings.ToLower(host)
for _, restricted := range []string{"localhost" /* + restrictedHostnames list */} {
    if h == restricted {
        return fmt.Errorf("hostname %s is restricted; use the service's routable name or whitelist it", host)
    }
}

Try / catch

conn, err := utils.SSRFSafeDialContext(ctx, "tcp", addr)
if err != nil && strings.Contains(err.Error(), "hostname") && strings.Contains(err.Error(), "is restricted") {
    return nil, fmt.Errorf("restricted destination hostname (configure whitelist if intended): %w", err)
}

Prevention

When it happens

Trigger: Calling SSRFSafeDialContext / SSRFSafeGRPCDialer (directly or as http.Transport.DialContext) with addr whose host equals a restricted hostname like "localhost" or a metadata hostname, and the host is not whitelisted. TestSSRFSafeDialContextRejectsRestrictedPortAtFinalSink exercises the final-sink path where this fires.

Common situations: Pointing the SSRF-safe client at http://localhost:port for local development; legacy configs using "metadata" style hostnames; tests that dial the local test server without a whitelist entry.

Related errors


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