apache/shenyu · error · IllegalArgumentException
Resolved IP address is private: " + address.getHostAddress()
Error message
Resolved IP address is private: " + address.getHostAddress()
What it means
validateHostForSSRF performs a second pass over each DNS-resolved address using the custom isPrivateIPAddress() range check (beyond InetAddress's built-in flags). If any resolved IP falls in a configured private range, it throws this IllegalArgumentException. It exists to catch private ranges the JDK flags do not cover.
Solutions
- Use a hostname that resolves to a public address.
- If your environment legitimately uses these ranges, route through a public proxy endpoint instead.
- For tests, extend the private-range list only in test scopes; keep production ranges strict.
Example fix
// before
UrlSecurityUtils.validateUrlForSSRF("http://svc.internal:8080"); // resolves to 100.64.1.5
// after
UrlSecurityUtils.validateUrlForSSRF("https://svc.example.com"); Defensive patterns
Strategy: try-catch
Validate before calling
InetAddress[] addrs = InetAddress.getAllByName(host);
for (InetAddress a : addrs) {
if (isPrivateIPAddress(a.getHostAddress())) {
throw new IllegalArgumentException("resolves to private range: " + a.getHostAddress());
}
} Type guard
boolean allResolvedIpsPublic(String host) throws UnknownHostException {
return Arrays.stream(InetAddress.getAllByName(host))
.allMatch(a -> !isPrivateIPAddress(a.getHostAddress()));
} Try / catch
try {
UrlSecurityUtils.validateUrlForSSRF(url);
} catch (IllegalArgumentException e) {
log.warn("Resolved IP in private range: {}", e.getMessage());
} Prevention
- Know your network's address plan (CGNAT, corporate ranges) before registering URLs.
- Front internal services with a public-facing gateway endpoint.
- Test hostname resolution from the admin host, not your laptop.
When it happens
Trigger: Validating a hostname whose DNS resolves to an IP matched by isPrivateIPAddress() (e.g. CGNAT 100.64.x, other internal CIDR ranges), even when InetAddress.isSiteLocalAddress() returns false.
Common situations: Deployments behind NAT64/CGNAT or corporate ranges (100.64.0.0/10, 198.18.0.0/15) where the service hostname legitimately resolves to such addresses.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- Resolved IP address is not allowed: " +…
- URL cannot be empty
- Invalid URL format
- Only HTTP and HTTPS protocols are allowed
- Host cannot be empty
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/ecf14e21ece87736.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/UrlSecurityUtils.java:111
}
// Check for sensitive ports
if (isSensitivePort(port)) {
throw new IllegalArgumentException("Access to sensitive ports is not allowed");
}
// Additional validation for DNS resolution
try {
InetAddress[] addresses = InetAddress.getAllByName(normalizedHost);
for (InetAddress address : addresses) {
if (address.isLoopbackAddress() || address.isLinkLocalAddress()
|| address.isSiteLocalAddress() || address.isAnyLocalAddress()) {
throw new IllegalArgumentException("Resolved IP address is not allowed: " + address.getHostAddress());
}
// Check resolved IP against private ranges
if (isPrivateIPAddress(address.getHostAddress())) {
throw new IllegalArgumentException("Resolved IP address is private: " + address.getHostAddress());
}
}
} catch (UnknownHostException e) {
throw new IllegalArgumentException("Cannot resolve host: " + host);
}
}
/**
* Check if the host is localhost or localhost variations.
*
* @param host the host to check
* @return true if the host is localhost
*/
private static boolean isLocalhost(final String host) {
Set<String> localhostVariations = new HashSet<>(Arrays.asList(
"localhost", "127.0.0.1", "::1", "0.0.0.0", "0000:0000:0000:0000:0000:0000:0000:0001"
));
return localhostVariations.contains(host);View on GitHub (pinned to 567142e072)