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
- Reject and investigate — this is a potential SSRF attack vector, not a configuration issue
- If legitimate, deploy the agent behind a public DNS name that does not resolve to metadata addresses
- Ensure the agentUrl hostname resolves to the agent's actual public or allowed private IP
- 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
- Never allow user-supplied URLs that resolve to 169.254.x.x
- Treat this error as a potential security incident and investigate the source of the URL
- Block cloud metadata IP ranges at the network/firewall layer in addition to application checks
- Use SSRF protection at the network layer (egress firewall rules) for defense in depth
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
- agentUrl must use http or https, got: {scheme}
- agentUrl resolves to a private/reserved address — SSRF block
- agentUrl must not be blank
- agentUrl is not a valid URL: {rawUrl} — {message}
- Access denied: host '{host}' is blocked
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/0a7304df31c76673.
Report an issue: GitHub.