{"record":{"id":"3c021faf5d4fd1ab","repo":"Tencent/WeKnora","slug":"connection-blocked-hostname-s-is-restricted","errorCode":null,"errorMessage":"connection blocked: hostname %s is restricted","messagePattern":"connection blocked: hostname (.+?) is restricted","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":817,"sourceCode":"\t// ValidateURLForSSRF which skips isSSRFSafeURL for whitelisted hosts.\n\t// NOTE: This intentionally relaxes DNS-rebinding protection for whitelisted\n\t// hosts. Admins must ensure whitelisted domains are under their control.\n\tif IsSystemProxy(addr) || IsSSRFWhitelisted(host) {\n\t\tdialer := &net.Dialer{\n\t\t\tTimeout:   30 * time.Second,\n\t\t\tKeepAlive: 30 * time.Second,\n\t\t}\n\t\treturn dialer.DialContext(ctx, network, addr)\n\t}\n\tif restrictedPorts[port] {\n\t\treturn nil, fmt.Errorf(\"connection blocked: port %s is restricted\", port)\n\t}\n\n\t// Check if the host is a restricted hostname\n\thostLower := strings.ToLower(host)\n\tfor _, restricted := range restrictedHostnames {\n\t\tif hostLower == restricted {\n\t\t\treturn nil, fmt.Errorf(\"connection blocked: hostname %s is restricted\", host)\n\t\t}\n\t}\n\tfor _, suffix := range restrictedHostSuffixes {\n\t\tif strings.HasSuffix(hostLower, suffix) {\n\t\t\treturn nil, fmt.Errorf(\"connection blocked: hostname suffix %s is restricted\", suffix)\n\t\t}\n\t}\n\n\t// Resolve the hostname once, validate every answer, and then dial one of\n\t// those exact IPs. Dialing the original hostname here would make the\n\t// standard dialer resolve it a second time, leaving a DNS-rebinding window\n\t// between validation and connection establishment.\n\tips, err := net.DefaultResolver.LookupIPAddr(ctx, host)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"DNS resolution failed for %s: %w\", host, err)\n\t}\n\tif len(ips) == 0 {\n\t\treturn nil, fmt.Errorf(\"DNS resolution returned no addresses for %s\", host)","sourceCodeStart":799,"sourceCodeEnd":835,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L799-L835","documentation":"SSRFSafeDialContext blocked the connection because the hostname exactly matches an entry in the restrictedHostnames list. Names such as localhost or cloud metadata hostnames are denied at dial time as a second layer of defense behind URL validation. The comparison is case-insensitive (strings.ToLower), so casing tricks do not bypass it.","triggerScenarios":"Calling SSRFSafeDialContext / SSRFSafeGRPCDialer (directly or as http.Transport.DialContext) with addr whose host equals a restricted hostname like \"localhost\" or a metadata hostname, and the host is not whitelisted. TestSSRFSafeDialContextRejectsRestrictedPortAtFinalSink exercises the final-sink path where this fires.","commonSituations":"Pointing the SSRF-safe client at http://localhost:port for local development; legacy configs using \"metadata\" style hostnames; tests that dial the local test server without a whitelist entry.","solutions":["Dial the service using a non-restricted hostname or its routable public name instead of the restricted hostname.","For trusted internal endpoints, register the host in the SSRF whitelist so dial-time checks are skipped for it.","In tests, use a whitelisted test host or inject the whitelist before dialing rather than using \"localhost\".","Confirm the exact restricted list in internal/utils/security.go and rename your service host if it collides accidentally."],"exampleFix":"// before\nconn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", \"localhost:8080\")\n\n// after\nconn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", \"api.internal.example.com:8080\") // or add host to whitelist","handlingStrategy":"validation","validationCode":"host, _, _ := net.SplitHostPort(addr)\nh := strings.ToLower(host)\nfor _, restricted := range []string{\"localhost\" /* + restrictedHostnames list */} {\n    if h == restricted {\n        return fmt.Errorf(\"hostname %s is restricted; use the service's routable name or whitelist it\", host)\n    }\n}","typeGuard":null,"tryCatchPattern":"conn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", addr)\nif err != nil && strings.Contains(err.Error(), \"hostname\") && strings.Contains(err.Error(), \"is restricted\") {\n    return nil, fmt.Errorf(\"restricted destination hostname (configure whitelist if intended): %w\", err)\n}","preventionTips":["Use routable service names instead of localhost/metadata hostnames in configuration.","Add trusted internal hosts to the SSRF whitelist during deployment setup.","Never hardcode localhost endpoints in production code paths.","Review hostnames against the restrictedHostnames list when onboarding new services."],"tags":["ssrf","restricted-hostname","dial","security-policy"],"backgroundTag":"host-blocked","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}