koala73/worldmonitor · error · McpProxySsrfError
serverUrl hostname is blocked: ${hostname}
Error message
serverUrl hostname is blocked: ${hostname} What it means
Thrown by assertServerUrlSafe when the lowercased serverUrl hostname is in BLOCKED_HOSTNAMES (localhost, metadata, metadata.internal, metadata.google.internal, instance-data, computemetadata, link-local.s3.amazonaws.com, 169.254.169.254). This is the static cloud-metadata/localhost SSRF gate that runs before any DNS resolution. The hostname is interpolated into the message because it is already non-secret caller input.
Source
Thrown at api/mcp-proxy.ts:157
return (Array.isArray(data?.Answer) ? data.Answer : [])
.filter(answer => answer?.type === expectedType && typeof answer?.data === 'string')
.map(answer => answer.data);
}
async function defaultResolveHostname(hostname) {
const resolveHostnameForTest = getResolveHostnameForTest();
if (resolveHostnameForTest) return resolveHostnameForTest(hostname);
const records = await Promise.all([
resolveDnsJson(hostname, 'A'),
resolveDnsJson(hostname, 'AAAA'),
]);
return records.flat();
}
async function assertServerUrlSafe(url) {
const hostname = url.hostname.toLowerCase();
if (BLOCKED_HOSTNAMES.has(hostname)) {
throw new McpProxySsrfError(`serverUrl hostname is blocked: ${hostname}`);
}
if (isBlockedResolvedAddress(hostname)) {
throwBlockedAddress(hostname);
}
let resolvedAddresses;
try {
resolvedAddresses = await defaultResolveHostname(hostname);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new McpProxySsrfError(`serverUrl DNS resolution failed: ${message}`);
}
if (!resolvedAddresses.length) {
throw new McpProxySsrfError('serverUrl DNS resolution returned no addresses');
}
const blocked = resolvedAddresses.find(isBlockedResolvedAddress);View on GitHub (pinned to ffec79ac33)
Solutions
- Use a public https MCP server URL.
- For local dev, expose the local MCP server via an https tunnel before pointing the proxy at it.
- Remove any metadata/localhost hostnames from MCP config fixtures.
Example fix
// before
proxy({ serverUrl: 'https://localhost:8080/mcp' })
// after
proxy({ serverUrl: 'https://mcp-tunnel.example.dev/mcp' }) Defensive patterns
Strategy: validation
Validate before calling
const BLOCKED_HOSTNAMES = new Set([
'localhost','metadata','metadata.internal','metadata.google.internal',
'instance-data','computemetadata','link-local.s3.amazonaws.com','169.254.169.254',
]);
function serverUrlHostBlocked(rawUrl: string): boolean {
try { return BLOCKED_HOSTNAMES.has(new URL(rawUrl).hostname.toLowerCase()); }
catch { return false; }
} Type guard
function isAllowedMcpHostname(value: unknown): boolean {
if (typeof value !== 'string') return false;
try { return !BLOCKED_HOSTNAMES.has(new URL(value).hostname.toLowerCase()); } catch { return false; }
} Try / catch
try {
await assertServerUrlSafe(new URL(serverUrl));
} catch (err) {
if (err.name === 'McpProxySsrfError' && err.message.startsWith('serverUrl hostname is blocked:')) {
return res.status(400).json({ error: 'That MCP server hostname is blocked.' });
}
throw err;
} Prevention
- Never configure the proxy with localhost or metadata hostnames; use public hostnames or https tunnels for local dev.
- Keep test fixtures pointed at public test sinks.
- Extend BLOCKED_HOSTNAMES if your infra adds new metadata endpoints.
When it happens
Trigger: POST /api/mcp-proxy with a serverUrl whose host is one of the blocked metadata/localhost literals, e.g. `https://169.254.169.254/`, `https://metadata.google.internal/`, or `https://localhost:8080/`.
Common situations: Local dev pointing the MCP proxy at localhost; an adversarial SSRF probe against cloud metadata; a stale config pointing at a metadata hostname.
Related errors
- serverUrl host is not allowed
- Webhook URL must not point to a metadata endpoint
- serverUrl DNS resolution failed: ${message}
- serverUrl DNS resolution returned no addresses
- Webhook URL must not point to a private/local address
AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12).
Data as JSON: /api/errors/6bb817e301945a8d.
Report an issue: GitHub.