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
- Change the redirect target to a publicly routable host that resolves only to public IPs.
- If access to the internal host is intended, adjust the guard allowlist rather than bypassing the check.
- 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
- Keep public-facing redirects pointed at publicly routable hosts only.
- Watch for split-horizon DNS names leaking into public redirect responses.
- If internal access is intentional, request an explicit guard allowlist change rather than bypassing.
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
- redirect to blocked IP %s denied
- URL scheme must be https, got %q
- URL host must be an allowed FHIR host, got %q
- failed to resolve redirect host %s: %w
- path must be relative and cannot override base host
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/2541003a64b41e75.
Report an issue: GitHub.