{"record":{"id":"37e8dc0fbcb66d7d","repo":"Tencent/WeKnora","slug":"invalid-address-s-w-37e8dc","errorCode":null,"errorMessage":"invalid address %s: %w","messagePattern":"invalid address (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":795,"sourceCode":"// upstream should share one NewSSRFSafeTransport via NewSSRFSafeHTTPClientWithTransport instead.\nfunc NewSSRFSafeHTTPClient(config SSRFSafeHTTPClientConfig) *http.Client {\n\treturn NewSSRFSafeHTTPClientWithTransport(config, NewSSRFSafeTransport(config))\n}\n\n// SSRFSafeGRPCDialer is compatible with grpc.WithContextDialer and pins DNS\n// answers the same way as SSRFSafeDialContext.\nfunc SSRFSafeGRPCDialer(ctx context.Context, addr string) (net.Conn, error) {\n\treturn SSRFSafeDialContext(ctx, \"tcp\", addr)\n}\n\n// SSRFSafeDialContext is a custom dial function that validates the resolved IP addresses\n// before establishing a connection. This provides an additional layer of SSRF protection\n// against DNS rebinding attacks during the connection phase.\nfunc SSRFSafeDialContext(ctx context.Context, network, addr string) (net.Conn, error) {\n\t// Parse host and port\n\thost, port, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid address %s: %w\", addr, err)\n\t}\n\n\t// Whitelisted hosts bypass all dial-time SSRF checks, consistent with\n\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","sourceCodeStart":777,"sourceCodeEnd":813,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L777-L813","documentation":"SSRFSafeDialContext could not parse the address into host and port because net.SplitHostPort failed. The dialer requires addresses in \"host:port\" form (with brackets for IPv6 literals) to run its dial-time SSRF checks; a malformed address means it cannot even begin validation. The wrapped error (%w) states whether the problem is a missing port, too many colons, or similar.","triggerScenarios":"Passing an address without a port (\"localhost\"), an unbracketed IPv6 literal (\"::1:8080\"), an empty string, or an address with extra colons into SSRFSafeDialContext, SSRFSafeGRPCDialer, or a custom dial function that delegates to it (e.g. DialContext on http.Transport wired to it). TestSSRFSafeDialContextRejectsRestrictedPortAtFinalSink calls it with the addresses produced by the transport, so a malformed addr from configuration triggers this.","commonSituations":"Configuring a gRPC target as \"myhost\" instead of \"myhost:443\"; hand-building proxy addresses and forgetting the port; pasting a URL (\"http://host:port\") where a host:port dial address is expected; IPv6 endpoints missing square brackets.","solutions":["Fix the address string to include an explicit port, e.g. \"localhost:8080\" or \"[::1]:8080\" for IPv6.","If the address comes from config or environment, normalize it before dialing: run net.SplitHostPort yourself and default the port when missing.","For gRPC, ensure the target includes the port (grpc.NewClient(\"dns:///host:443\", ...)) or use a resolver dial option.","Strip any scheme before passing the address: parse with net/url and pass u.Host, not the full URL."],"exampleFix":"// before\ndialer := &net.Dialer{...}\nconn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", \"my-internal-service\")\n\n// after\naddr := \"my-internal-service\"\nif _, _, err := net.SplitHostPort(addr); err != nil {\n    addr = net.JoinHostPort(addr, \"443\")\n}\nconn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", addr)","handlingStrategy":"validation","validationCode":"if _, _, err := net.SplitHostPort(addr); err != nil {\n    return fmt.Errorf(\"dial address %q is not host:port: %w\", addr, err)\n}","typeGuard":null,"tryCatchPattern":"conn, err := utils.SSRFSafeDialContext(ctx, \"tcp\", addr)\nif err != nil && strings.Contains(err.Error(), \"invalid address\") {\n    return nil, fmt.Errorf(\"misconfigured dial address %q (expected host:port): %w\", addr, err)\n}","preventionTips":["Normalize addresses with net.JoinHostPort; bracket IPv6 literals.","Pass u.Host from a parsed URL, never the full URL string, to dial functions.","Default missing ports explicitly in configuration loading.","Validate all dial addresses at config-load time, not at request time."],"tags":["network","dial","address-format","ssrf"],"backgroundTag":"invalid-address-format","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}