micro/go-micro · error

push callback scheme %q not allowed (want http or https)

Error message

push callback scheme %q not allowed (want http or https)

What it means

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.

Source

Thrown at gateway/a2a/pushsecurity.go:36

//
// The default policy allows only http/https callbacks whose host does not
// resolve to a loopback, private, link-local, or unspecified address, and the
// guarded HTTP client re-checks the *resolved* IP at dial time so a hostname
// that passes validation cannot be rebound to an internal address before the
// connection is made. Operators who need to reach a trusted in-cluster
// receiver set Options.AllowPushURL to take over the policy.

// pushLookupIP resolves a host to IPs; overridable in tests.
var pushLookupIP = net.LookupIP

// defaultPushURLPolicy is the SSRF-safe policy applied when no AllowPushURL is
// configured. It rejects non-http(s) schemes and hosts that resolve to a
// loopback, private, link-local, multicast, or unspecified address.
func defaultPushURLPolicy(u *url.URL) error {
	switch u.Scheme {
	case "http", "https":
	default:
		return fmt.Errorf("push callback scheme %q not allowed (want http or https)", u.Scheme)
	}
	host := u.Hostname()
	if host == "" {
		return fmt.Errorf("push callback url has no host")
	}
	ips, err := resolvePushHost(host)
	if err != nil {
		return fmt.Errorf("push callback host %q: %w", host, err)
	}
	if len(ips) == 0 {
		return fmt.Errorf("push callback host %q did not resolve", host)
	}
	for _, ip := range ips {
		if blockedPushIP(ip) {
			return fmt.Errorf("push callback host %q resolves to a blocked address %s", host, ip)
		}
	}
	return nil

View on GitHub (pinned to 24529f1404)

Solutions

  1. Ensure the callback URL starts with http:// or https:// (prefer https in production).
  2. Validate/sanitize user-provided webhook URLs at your application boundary before passing them to the library.
  3. Parse the URL yourself with net/url and check u.Scheme before constructing the push config request.

Example fix

// before
webhook := "file:///tmp/callback" // or "agents.example.com/hook" (no scheme)
// after
webhook := "https://agents.example.com/hook"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(callback)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
	return fmt.Errorf("callback must be http(s): %q", callback)
}

Type guard

func isHTTPScheme(u *url.URL) bool {
	return u != nil && (u.Scheme == "http" || u.Scheme == "https")
}

Prevention

When it happens

Trigger: Calling SetPushNotificationConfig / PushNotificationConfig with a callback URL like 'file:///etc/passwd', 'gopher://...', or an empty/garbled scheme string.

Common situations: 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.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/0a0fb3663f333dc4. Report an issue: GitHub.