Tencent/WeKnora · error

connection blocked: port %s is restricted

Error message

connection blocked: port %s is restricted

What it means

SSRFSafeDialContext refused to open the connection because the destination port is in the library's restrictedPorts set. Certain ports (e.g. SMTP 25 and other services commonly abused for SSRF pivoting) are unconditionally blocked at dial time regardless of the host. This is an intentional security denial, not a connectivity problem.

Source

Thrown at internal/utils/security.go:810

	// Parse host and port
	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, fmt.Errorf("invalid address %s: %w", addr, err)
	}

	// Whitelisted hosts bypass all dial-time SSRF checks, consistent with
	// 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

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Move the service to a non-restricted port (e.g. 443/8443 for HTTPS) and update the client configuration.
  2. If the host must stay as is, add it to the SSRF whitelist so dial-time checks are bypassed for that trusted host.
  3. Check the restrictedPorts list in internal/utils/security.go to confirm the port is blocked and pick an allowed alternative.
  4. Use a plain (non-SSRF-guarded) dialer only if you fully control the destination and accept losing the SSRF/DNS-rebinding protection.

Example fix

// before
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "mail.example.com:25")

// after
conn, err := utils.SSRFSafeDialContext(ctx, "tcp", "mail.example.com:587") // or whitelist the host
Defensive patterns

Strategy: validation

Validate before calling

_, port, _ := net.SplitHostPort(addr)
if n, err := strconv.Atoi(port); err == nil && utils.IsRestrictedPort(n) { // or check against restrictedPorts list
    return fmt.Errorf("port %s is restricted by SSRF policy; choose another port", port)
}

Try / catch

conn, err := utils.SSRFSafeDialContext(ctx, "tcp", addr)
if err != nil && strings.Contains(err.Error(), "port") && strings.Contains(err.Error(), "restricted") {
    return nil, fmt.Errorf("destination port not allowed by security policy: %w", err)
}

Prevention

When it happens

Trigger: Dialing via SSRFSafeDialContext / SSRFSafeGRPCDialer (or an http.Transport whose DialContext is SSRFSafeDialContext) to any address whose port maps to true in the restrictedPorts map, after the whitelisted-host bypass is not taken. The test TestSSRFSafeDialContextRejectsRestrictedPortAtFinalSink hits this at the final sink for a restricted port.

Common situations: Trying to send email through port 25 of a relay from inside the guarded client; pointing a gRPC/HTTP client at an admin service on a blocked port; migrating a service to a port that happens to be on the restricted list.

Related errors


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