{"record":{"id":"524f12a8d6aa8d42","repo":"micro/go-micro","slug":"push-callback-refusing-to-connect-to-blocked-addr","errorCode":null,"errorMessage":"push callback: refusing to connect to blocked address %s","messagePattern":"push callback: refusing to connect to blocked address (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gateway/a2a/pushsecurity.go","lineNumber":91,"sourceCode":"\t\tip.IsInterfaceLocalMulticast() ||\n\t\tip.IsMulticast() ||\n\t\tip.IsUnspecified()\n}\n\n// pushDialControl runs after DNS resolution, immediately before connect, on the\n// resolved address — so it blocks a host that passed URL validation but was\n// rebound to an internal IP (DNS rebinding).\nfunc pushDialControl(_, address string, _ syscall.RawConn) error {\n\thost, _, err := net.SplitHostPort(address)\n\tif err != nil {\n\t\treturn err\n\t}\n\tip := net.ParseIP(host)\n\tif ip == nil {\n\t\treturn fmt.Errorf(\"push callback: cannot parse dial address %q\", address)\n\t}\n\tif blockedPushIP(ip) {\n\t\treturn fmt.Errorf(\"push callback: refusing to connect to blocked address %s\", ip)\n\t}\n\treturn nil\n}\n\n// pushGuardClient is the HTTP client used for default-policy push delivery. Its\n// dialer refuses connections to blocked addresses at connect time.\nvar pushGuardClient = &http.Client{\n\tTimeout: 10 * time.Second,\n\tTransport: &http.Transport{\n\t\tProxy: http.ProxyFromEnvironment,\n\t\tDialContext: (&net.Dialer{\n\t\t\tTimeout: 5 * time.Second,\n\t\t\tControl: pushDialControl,\n\t\t}).DialContext,\n\t},\n}\n\n// checkPushURL validates a callback URL against the dispatcher's effective","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/gateway/a2a/pushsecurity.go#L73-L109","documentation":"pushDialControl rejects dialing addresses whose parsed IP is in the blocked set (private, loopback, link-local ranges per blockedPushIP). This SSRF protection prevents push notifications from being used to reach internal infrastructure. The error is raised at connect time when the callback target resolves to a forbidden address.","triggerScenarios":"A push callback URL points at (or resolves to) a blocked IP such as 127.0.0.1, 10.x.x.x, 172.16.x.x, 192.168.x.x, or 169.254.169.254, and a push delivery attempt dials it under the default SSRF policy.","commonSituations":"Developers testing against a local push receiver on localhost; misconfigured callbacks pointing at internal cluster services; attackers supplying callback URLs targeting cloud metadata endpoints (169.254.169.254).","solutions":["Point the push callback at a public, non-blocked IP address.","Expose the local receiver via a public tunnel/host and use that public address in the callback URL.","If internal callbacks are intentionally required, configure a custom AllowPushURL policy / dial control that explicitly allows the specific internal range."],"exampleFix":"// before\nsetPushConfig(task, \"http://127.0.0.1:9090/push\")\n// after\nsetPushConfig(task, \"https://push.example.com/push\") // public address, not blocked","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(callbackURL)\nip := net.ParseIP(u.Hostname())\nif ip != nil && (ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast()) {\n    return fmt.Errorf(\"callback %s targets a blocked address\", ip)\n}","typeGuard":"func isPublicIP(rawURL string) bool {\n    u, err := url.Parse(rawURL)\n    if err != nil { return false }\n    ip := net.ParseIP(u.Hostname())\n    return ip != nil && !ip.IsLoopback() && !ip.IsPrivate() && !ip.IsLinkLocalUnicast()\n}","tryCatchPattern":null,"preventionTips":["Never point push callbacks at localhost, private ranges, or metadata endpoints.","Expose local test receivers through a public tunnel instead of using 127.0.0.1.","Document any custom AllowPushURL policy relaxations and restrict them to explicit CIDR allowlists."],"tags":["ssrf","push-callback","security","blocked-address"],"backgroundTag":"ssrf-blocked-address","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}