googleapis/mcp-toolbox · error

redirect host %s resolves to blocked IP %s

Error message

redirect host %s resolves to blocked IP %s

What it means

After resolving a redirect hostname, each returned address is checked with guard.IsIPBlocked; if any address is in a blocked (private/loopback/metadata) range, the redirect is denied with this error. This closes the DNS-rebinding/SSRF hole where a hostname resolves to an internal IP even though the URL looks public.

Source

Thrown at internal/sources/http/http.go:375

			}

			hostname := req.URL.Hostname()
			if ip := net.ParseIP(hostname); ip != nil {
				if guard.IsIPBlocked(ip) {
					return fmt.Errorf("redirect to blocked IP %s denied", ip)
				}
				return nil
			}

			addrs, err := resolver.LookupHost(req.Context(), hostname)
			if err != nil {
				return fmt.Errorf("failed to resolve redirect host %s: %w", hostname, err)
			}

			for _, addr := range addrs {
				if ip := net.ParseIP(addr); ip != nil {
					if guard.IsIPBlocked(ip) {
						return fmt.Errorf("redirect host %s resolves to blocked IP %s", hostname, addr)
					}
				}
			}

			return nil
		},
	}
	return client, nil
}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Change the redirect target to a publicly routable host that resolves only to public IPs.
  2. If access to the internal host is intended, adjust the guard allowlist rather than bypassing the check.
  3. Audit which service issues the redirect and remove internal-host references from public responses.

Example fix

// before: Location: https://internal-svc.corp.local/api (resolves to 10.0.1.5)
// after: expose via a public, allowlisted endpoint
w.Header().Set("Location", "https://api.example.com/api")
Defensive patterns

Strategy: validation

Validate before calling

const host = new URL(redirectTarget).hostname;
const addrs = await require('dns').promises.lookup(host, { all: true });
const isPrivate = a => /^(10\.|127\.|192\.168\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.)/.test(a.address);
if (addrs.some(isPrivate)) console.warn(`redirect host ${host} resolves to a private IP; it will be denied by the SSRF guard`);

Try / catch

try {
  const result = await callHttpTool(url);
} catch (err) {
  if (/redirect host .* resolves to blocked IP/.test(String(err))) {
    console.error('Redirect hostname resolves to an internal IP; point it at a public endpoint instead.');
  } else throw err;
}

Prevention

When it happens

Trigger: A redirect whose hostname resolves (via LookupHost) to at least one IP classified as blocked by the guard, e.g. an internal DNS name or a hostname resolving to 10.x/127.x/169.254.x.

Common situations: Redirect to an internal service hostname that only resolves inside the VPC; split-horizon DNS returning private addresses; attacker-controlled DNS mapping a public name to 169.254.169.254.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/2541003a64b41e75. Report an issue: GitHub.