conductor-oss/conductor · critical · NonRetryableException

agentUrl resolves to a cloud metadata address — SSRF blocked

Error message

agentUrl resolves to a cloud metadata address — SSRF blocked: {address}

What it means

Thrown by A2AService.validateAgentUrl() when the agentUrl hostname resolves to a cloud metadata endpoint address (IPv4 169.254.x.x or IPv6 fd00:ec2::254 / fe80::a9fe:a9fe). This SSRF guard blocks access to AWS IMDS, ECS metadata, and equivalent GCP/Azure endpoints even when private networks are explicitly allowed. It is a NonRetryableException.

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/a2a/A2AService.java:448

     * behind a network-layer firewall that blocks egress to private ranges.
     */
    public void validateAgentUrl(String rawUrl) {
        if (rawUrl == null || rawUrl.isBlank()) {
            throw new NonRetryableException("agentUrl must not be blank");
        }
        try {
            URL url = new URL(rawUrl.trim());
            String scheme = url.getProtocol();
            if (!"http".equals(scheme) && !"https".equals(scheme)) {
                throw new NonRetryableException("agentUrl must use http or https, got: " + scheme);
            }
            String host = url.getHost();
            InetAddress[] addresses = InetAddress.getAllByName(host);
            for (InetAddress addr : addresses) {
                // Cloud metadata endpoints are blocked even when private networks are allowed.
                if (isMetadataAddress(addr)) {
                    A2AMetrics.ssrfBlocked();
                    throw new NonRetryableException(
                            "agentUrl resolves to a cloud metadata address — SSRF blocked: "
                                    + addr.getHostAddress());
                }
                if (allowPrivateNetwork) {
                    continue;
                }
                if (addr.isLoopbackAddress()
                        || addr.isSiteLocalAddress()
                        || addr.isLinkLocalAddress()
                        || addr.isAnyLocalAddress()
                        || isUniqueLocalIpv6(addr)) {
                    A2AMetrics.ssrfBlocked();
                    throw new NonRetryableException(
                            "agentUrl resolves to a private/reserved address — SSRF blocked: "
                                    + addr.getHostAddress()
                                    + " (set "
                                    + ALLOW_PRIVATE_NETWORK_PROPERTY
                                    + "=true to allow private-network agents)");

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Reject and investigate — this is a potential SSRF attack vector, not a configuration issue
  2. If legitimate, deploy the agent behind a public DNS name that does not resolve to metadata addresses
  3. Ensure the agentUrl hostname resolves to the agent's actual public or allowed private IP
  4. If using a local agent, set conductor.a2a.client.allow-private-network=true AND use a non-metadata private address
Defensive patterns

Strategy: validation

Validate before calling

// Reject metadata addresses before calling A2A (defensive, in addition to the built-in guard)
try {
    InetAddress[] addrs = InetAddress.getAllByName(new URL(agentUrl).getHost());
    for (InetAddress addr : addrs) {
        byte[] b = addr.getAddress();
        if (b.length == 4 && (b[0] & 0xFF) == 169 && (b[1] & 0xFF) == 254) {
            throw new SecurityException("URL resolves to cloud metadata endpoint");
        }
    }
} catch (Exception e) {
    // handle
}

Try / catch

try {
    a2aService.validateAgentUrl(agentUrl);
} catch (NonRetryableException e) {
    if (e.getMessage().contains("cloud metadata")) {
        // Potential SSRF attack — log and investigate
        log.error("SSRF attempt blocked: {}", e.getMessage());
        SecurityAudit.log(agentUrl, "SSRF_METADATA_BLOCKED");
    }
    throw e;
}

Prevention

When it happens

Trigger: The agentUrl's hostname DNS-resolves to an IP in the 169.254.0.0/16 range (AWS IMDS 169.254.169.254, ECS 169.254.170.2) or matches known IPv6 metadata addresses. This check runs unconditionally — it cannot be overridden by the allow-private-network property.

Common situations: A malicious actor supplies an agentUrl that resolves to 169.254.169.254 to steal cloud credentials (IMDSv1). A DNS rebinding attack points a legitimate-looking hostname to a metadata IP. A misconfigured internal hostname accidentally resolves to the link-local range.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/0a7304df31c76673. Report an issue: GitHub.