{"record":{"id":"253a11b9e0792b71","repo":"apache/shenyu","slug":"access-to-localhost-is-not-allowed","errorCode":null,"errorMessage":"Access to localhost is not allowed","messagePattern":"Access to localhost is not allowed","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/UrlSecurityUtils.java","lineNumber":87,"sourceCode":"    }\n\n    /**\n     * Validate host to prevent SSRF attacks.\n     *\n     * @param host the host to validate\n     * @param port the port to validate\n     * @throws IllegalArgumentException if the host is not allowed\n     */\n    public static void validateHostForSSRF(final String host, final int port) {\n        if (Objects.isNull(host) || host.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Host cannot be empty\");\n        }\n\n        String normalizedHost = host.toLowerCase().trim();\n\n        // Check for localhost variations\n        if (isLocalhost(normalizedHost)) {\n            throw new IllegalArgumentException(\"Access to localhost is not allowed\");\n        }\n\n        // Check for private IP addresses\n        if (isPrivateOrInternalIP(normalizedHost)) {\n            throw new IllegalArgumentException(\"Access to private or internal IP addresses is not allowed\");\n        }\n\n        // Check for sensitive ports\n        if (isSensitivePort(port)) {\n            throw new IllegalArgumentException(\"Access to sensitive ports is not allowed\");\n        }\n\n        // Additional validation for DNS resolution\n        try {\n            InetAddress[] addresses = InetAddress.getAllByName(normalizedHost);\n            for (InetAddress address : addresses) {\n                if (address.isLoopbackAddress() || address.isLinkLocalAddress()\n                        || address.isSiteLocalAddress() || address.isAnyLocalAddress()) {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/utils/UrlSecurityUtils.java#L69-L105","documentation":"As part of SSRF defense, validateHostForSSRF rejects hostnames that resolve to localhost (localhost, 127.x, ::1, etc.) and throws IllegalArgumentException \"Access to localhost is not allowed\". This prevents the admin server from being tricked into calling its own loopback interface where internal admin APIs would be reachable.","triggerScenarios":"Configuring a target URL whose host is 'localhost', '127.0.0.1', a loopback alias, or '0.0.0.0' — either by accident (admin meant a local dev backend) or as an SSRF attack payload.","commonSituations":"Developers testing in-container setups pointing the URL at localhost instead of the service's Docker DNS name; attackers submitting webhook/health-check URLs targeting the gateway's own loopback to hit internal admin endpoints.","solutions":["Use the backend service's real network address (container/service DNS name, LAN IP, or public domain) instead of localhost.","In Docker Compose/K8s, use service names (e.g. http://backend:8080) rather than localhost or 127.0.0.1.","Do not disable or bypass this check in production; it is an intentional SSRF safeguard.","If the private-network policy is too strict for your topology, adjust allowlists consciously with a security review rather than catching and ignoring the exception."],"exampleFix":"// before\nvalidateUrlForSSRF(\"http://localhost:8080/actuator/health\");\n// after\nvalidateUrlForSSRF(\"http://backend-service:8080/actuator/health\");","handlingStrategy":"try-catch","validationCode":"HttpUrl parsed = HttpUrl.parse(url);\nString host = parsed != null ? parsed.host().toLowerCase() : \"\";\nboolean isLoopback = \"localhost\".equals(host) || host.equals(\"127.0.0.1\")\n    || host.startsWith(\"127.\") || host.equals(\"::1\") || host.equals(\"0.0.0.0\");\nif (isLoopback) throw new IllegalArgumentException(\"localhost targets are not allowed\");","typeGuard":null,"tryCatchPattern":"try {\n    UrlSecurityUtils.validateUrlForSSRF(url);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Blocked localhost/internal target (SSRF guard): {}\", url);\n    return ResponseEntity.badRequest().body(\"localhost targets are not allowed\");\n}","preventionTips":["Use container/service DNS names (http://backend:8080) instead of localhost in Docker/K8s.","Record rejected loopback URLs — repeated attempts may indicate probing.","Educate users that 'localhost' from the admin server means the admin container itself.","Keep this SSRF guard enabled in all environments; it protects internal admin APIs."],"tags":["ssrf","security","localhost","url"],"backgroundTag":"permission-denied","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}