{"id":"372102673d6fea83","repo":"gofiber/fiber","slug":"proxy-invalid-dial-address-q-w","errorCode":null,"errorMessage":"proxy: invalid dial address %q: %w","messagePattern":"proxy: invalid dial address %q: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/proxy/security.go","lineNumber":433,"sourceCode":"\t}\n\treturn nil\n}\n\n// newSSRFDialer returns a fasthttp DialFunc that resolves the target host\n// (with a bounded timeout), rejects the connection if any resolved\n// address falls in a blocked range, and then dials a validated address.\n// Performing the check at dial time — rather than only up front — defeats\n// DNS-rebinding attacks (the check/use gap) where a resolver returns a\n// public address during validation and a private one at connect time. It\n// is only installed when the active policy disallows private IPs.\n//\n//nolint:revive // dialDualStack mirrors fasthttp.HostClient.DialDualStack\nfunc newSSRFDialer(dialDualStack bool) fasthttp.DialFunc {\n\tdialer := &net.Dialer{Timeout: dnsLookupTimeout}\n\treturn func(addr string) (net.Conn, error) {\n\t\thost, port, err := net.SplitHostPort(addr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"proxy: invalid dial address %q: %w\", addr, err)\n\t\t}\n\t\tips, err := resolveAndValidateHost(host)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn dialValidatedIPs(ips, host, port, dialDualStack, dialer.Dial)\n\t}\n}\n\n// resolveAndValidateHost looks up host (or treats it as an IP literal),\n// then enforces the SSRF blocklist on every returned address. A single\n// blocked answer fails the whole resolution so a mixed public/private\n// reply cannot slip past the guard.\nfunc resolveAndValidateHost(host string) ([]net.IP, error) {\n\tvar ips []net.IP\n\tif ip := net.ParseIP(host); ip != nil {\n\t\tips = []net.IP{ip}\n\t} else {","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/proxy/security.go#L415-L451","documentation":"Returned by the SSRF dialer (newSSRFDialer) when net.SplitHostPort cannot parse the address being dialed. This is an internal dial-path invariant failure on a malformed host:port string.","triggerScenarios":"The fasthttp dialer invokes the SSRF guard with an addr that net.SplitHostPort rejects (security.go:431-433), e.g. missing port, unbalanced brackets, or empty address. Normally fasthttp always supplies a valid host:port.","commonSituations":"A custom/malformed upstream address reaching the dialer; an IPv6 literal without brackets; a bug in upstream URL construction stripping the port.","solutions":["Ensure upstream URLs include an explicit host and port.","Wrap IPv6 literals in brackets, e.g. http://[::1]:8080.","Sanitize upstream config before it reaches the proxy."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure upstream URLs carry a host and port before proxying.\nfunc hasHostPort(raw string) error {\n    u, err := url.Parse(raw)\n    if err != nil { return err }\n    if u.Port() == \"\" || u.Hostname() == \"\" {\n        return fmt.Errorf(\"upstream must include host and port\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"invalid dial address\") {\n    return fiber.NewError(fiber.StatusBadGateway, \"malformed upstream address\")\n}","preventionTips":["Always include an explicit port in upstream URLs.","Bracket IPv6 literals: http://[::1]:8080.","Sanitize upstream config before it reaches the proxy."],"tags":["proxy","dialer","ssrf","address-parsing"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}