chenhg5/cc-connect · error

remote image host resolved to blocked IP %s

Error message

remote image host resolved to blocked IP %s

What it means

Part of SSRF protection: the custom dialer resolves the image host and checks each IP against isBlockedRichCardImageIP (private/loopback/link-local/metadata ranges). All candidate IPs were blocked, so the dial is refused and this error names the blocked IP for diagnosis.

Source

Thrown at platform/feishu/feishu.go:6673

		}
		for _, addr := range resolved {
			ips = append(ips, addr.IP)
		}
	}

	var firstBlocked net.IP
	for _, ip := range ips {
		if isBlockedRichCardImageIP(ip) {
			if firstBlocked == nil {
				firstBlocked = ip
			}
			continue
		}
		dialer := &net.Dialer{Timeout: richCardImageFinalWait}
		return dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), port))
	}
	if firstBlocked != nil {
		return nil, fmt.Errorf("remote image host resolved to blocked IP %s", firstBlocked.String())
	}
	return nil, errors.New("remote image host resolved to no usable IPs")
}

func isBlockedRichCardImageIP(ip net.IP) bool {
	addr, err := netip.ParseAddr(ip.String())
	if err != nil {
		return true
	}
	addr = addr.Unmap()
	return !addr.IsGlobalUnicast() ||
		addr.IsLoopback() ||
		addr.IsPrivate() ||
		addr.IsLinkLocalUnicast() ||
		addr.IsLinkLocalMulticast() ||
		addr.IsMulticast() ||
		addr.IsUnspecified() ||
		richCardImageIPInBlockedPrefix(addr)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Host the image on a genuinely public endpoint and update the URL
  2. If internal images are required, proxy them through a service with an approved egress path
  3. Check DNS records for the hostname — it must not resolve to RFC1918/link-local ranges
  4. Do not bypass the SSRF check; it protects against cloud metadata credential theft

Example fix

// before
"image_url": "http://internal-nas.local/photo.png"
// after
"image_url": "https://public-cdn.example.com/photo.png"
Defensive patterns

Strategy: validation

Validate before calling

ips, err := net.LookupHost(host)
// reject if any ip is private/loopback/link-local before configuring the URL

Prevention

When it happens

Trigger: A card image URL whose hostname resolves only to a blocked address — localhost, 127.0.0.1, 10.x/172.16.x/192.168.x, 169.254.x (cloud metadata), IPv6 loopback/ULA.

Common situations: Configured image URL using localhost or an internal hostname; DNS rebinding where public name resolves to internal IP; misconfigured internal CDN name; literal internal IP pasted as the image host.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/545b9a9d17cbe040. Report an issue: GitHub.