{"record":{"id":"0a0fb3663f333dc4","repo":"micro/go-micro","slug":"push-callback-scheme-q-not-allowed-want-http-or","errorCode":null,"errorMessage":"push callback scheme %q not allowed (want http or https)","messagePattern":"push callback scheme %q not allowed \\(want http or https\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gateway/a2a/pushsecurity.go","lineNumber":36,"sourceCode":"//\n// The default policy allows only http/https callbacks whose host does not\n// resolve to a loopback, private, link-local, or unspecified address, and the\n// guarded HTTP client re-checks the *resolved* IP at dial time so a hostname\n// that passes validation cannot be rebound to an internal address before the\n// connection is made. Operators who need to reach a trusted in-cluster\n// receiver set Options.AllowPushURL to take over the policy.\n\n// pushLookupIP resolves a host to IPs; overridable in tests.\nvar pushLookupIP = net.LookupIP\n\n// defaultPushURLPolicy is the SSRF-safe policy applied when no AllowPushURL is\n// configured. It rejects non-http(s) schemes and hosts that resolve to a\n// loopback, private, link-local, multicast, or unspecified address.\nfunc defaultPushURLPolicy(u *url.URL) error {\n\tswitch u.Scheme {\n\tcase \"http\", \"https\":\n\tdefault:\n\t\treturn fmt.Errorf(\"push callback scheme %q not allowed (want http or https)\", u.Scheme)\n\t}\n\thost := u.Hostname()\n\tif host == \"\" {\n\t\treturn fmt.Errorf(\"push callback url has no host\")\n\t}\n\tips, err := resolvePushHost(host)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"push callback host %q: %w\", host, err)\n\t}\n\tif len(ips) == 0 {\n\t\treturn fmt.Errorf(\"push callback host %q did not resolve\", host)\n\t}\n\tfor _, ip := range ips {\n\t\tif blockedPushIP(ip) {\n\t\t\treturn fmt.Errorf(\"push callback host %q resolves to a blocked address %s\", host, ip)\n\t\t}\n\t}\n\treturn nil","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/gateway/a2a/pushsecurity.go#L18-L54","documentation":"defaultPushURLPolicy is the SSRF guard applied to push-notification callback URLs before the library uses them. It throws this error when the callback URL's scheme is not http or https (e.g. file:, gopher:, ftp:), because non-HTTP schemes can be abused for local file or protocol attacks. The URL must be changed before a push config can be registered.","triggerScenarios":"Calling SetPushNotificationConfig / PushNotificationConfig with a callback URL like 'file:///etc/passwd', 'gopher://...', or an empty/garbled scheme string.","commonSituations":"User-supplied webhook URL passed through unvalidated; a config typo dropping the 'http(s)://' prefix so the URL parser yields an empty or wrong scheme; deliberately crafted input in a multi-tenant deployment.","solutions":["Ensure the callback URL starts with http:// or https:// (prefer https in production).","Validate/sanitize user-provided webhook URLs at your application boundary before passing them to the library.","Parse the URL yourself with net/url and check u.Scheme before constructing the push config request."],"exampleFix":"// before\nwebhook := \"file:///tmp/callback\" // or \"agents.example.com/hook\" (no scheme)\n// after\nwebhook := \"https://agents.example.com/hook\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(callback)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n\treturn fmt.Errorf(\"callback must be http(s): %q\", callback)\n}","typeGuard":"func isHTTPScheme(u *url.URL) bool {\n\treturn u != nil && (u.Scheme == \"http\" || u.Scheme == \"https\")\n}","tryCatchPattern":null,"preventionTips":["Always require https:// in production webhook configs","Sanitize user-supplied URLs at the application boundary","Reject bare-host strings missing a scheme during config load"],"tags":["security","ssrf","validation","url"],"backgroundTag":"invalid-url-scheme","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}