{"record":{"id":"eab2be5c22be0451","repo":"conductor-oss/conductor","slug":"agenturl-resolves-to-a-private-reserved-address","errorCode":null,"errorMessage":"agentUrl resolves to a private/reserved address — SSRF blocked: {address} (set {property}=true to allow private-network agents)","messagePattern":"agentUrl resolves to a private/reserved address — SSRF blocked: (.+?) \\(set (.+?)=true to allow private-network agents\\)","errorType":"validation","errorClass":"NonRetryableException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/a2a/A2AService.java","lineNumber":461,"sourceCode":"            InetAddress[] addresses = InetAddress.getAllByName(host);\n            for (InetAddress addr : addresses) {\n                // Cloud metadata endpoints are blocked even when private networks are allowed.\n                if (isMetadataAddress(addr)) {\n                    A2AMetrics.ssrfBlocked();\n                    throw new NonRetryableException(\n                            \"agentUrl resolves to a cloud metadata address — SSRF blocked: \"\n                                    + addr.getHostAddress());\n                }\n                if (allowPrivateNetwork) {\n                    continue;\n                }\n                if (addr.isLoopbackAddress()\n                        || addr.isSiteLocalAddress()\n                        || addr.isLinkLocalAddress()\n                        || addr.isAnyLocalAddress()\n                        || isUniqueLocalIpv6(addr)) {\n                    A2AMetrics.ssrfBlocked();\n                    throw new NonRetryableException(\n                            \"agentUrl resolves to a private/reserved address — SSRF blocked: \"\n                                    + addr.getHostAddress()\n                                    + \" (set \"\n                                    + ALLOW_PRIVATE_NETWORK_PROPERTY\n                                    + \"=true to allow private-network agents)\");\n                }\n            }\n        } catch (NonRetryableException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new NonRetryableException(\n                    \"agentUrl is not a valid URL: \" + rawUrl + \" — \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Cloud metadata endpoints, blocked even when private networks are allowed: IPv4 link-local\n     * 169.254.0.0/16 (AWS IMDS 169.254.169.254, ECS 169.254.170.2) and the IPv6 metadata addresses","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/a2a/A2AService.java#L443-L479","documentation":"Thrown by A2AService.validateAgentUrl() when the agentUrl resolves to a private, loopback, link-local, any-local, or IPv6 Unique Local Address (fc00::/7) and the allow-private-network property is false (default is true in the constructor, but may be overridden). This SSRF guard can be disabled by setting conductor.a2a.client.allow-private-network=true. It is a NonRetryableException.","triggerScenarios":"The agentUrl hostname resolves to an RFC-1918 address (10.x, 172.16-31.x, 192.168.x), loopback (127.x), link-local, 0.0.0.0, or IPv6 ULA — and conductor.a2a.client.allow-private-network is not set to true. The message includes the resolved IP and the property name to override.","commonSituations":"Testing with a local agent at http://localhost:8080 or http://127.0.0.1:port. The agent is deployed on an internal/private network. A development or staging environment where agents are on RFC-1918 addresses.","solutions":["Set the Spring property conductor.a2a.client.allow-private-network=true to allow private-network agents (the default is already true per the constructor, check if it was overridden to false)","Use a public DNS name for the agent that resolves to a public IP","If the agent must stay on a private network, ensure this is a deliberate security decision and document it","Note: even with allow-private-network=true, cloud metadata addresses (169.254.x.x) remain blocked"],"exampleFix":"# before: property not set or explicitly false\n# conductor.a2a.client.allow-private-network=false\n# after\nconductor.a2a.client.allow-private-network=true","handlingStrategy":"validation","validationCode":"// Check if the URL will be blocked by SSRF rules\n// If using private network agents, set the property first:\n// conductor.a2a.client.allow-private-network=true\n// Then validate:\na2aService.validateAgentUrl(agentUrl);","typeGuard":null,"tryCatchPattern":"try {\n    a2aService.validateAgentUrl(agentUrl);\n} catch (NonRetryableException e) {\n    if (e.getMessage().contains(\"private/reserved address\")) {\n        // If this is expected (internal agent), enable private network access\n        log.warn(\"Agent URL blocked by SSRF. If using internal agents, \"\n            + \"set conductor.a2a.client.allow-private-network=true\");\n    }\n    throw e;\n}","preventionTips":["Set conductor.a2a.client.allow-private-network=true in dev/staging if agents are on private networks","Document the security implications of allowing private network agents","For production, prefer public endpoints for A2A agents","Remember: even with allow-private-network=true, cloud metadata addresses remain blocked"],"tags":["a2a","ssrf","security","private-network","non-retryable"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}