musistudio/claude-code-router · error · Error

${label} cannot target a local or internal host.

Error message

${label} cannot target a local or internal host.

What it means

validateRemoteHostname blocks hostnames that resolve to local/internal scopes: 'localhost', '*.localhost', or suffixes .home, .lan, .local, .internal. Remote manifests must only target publicly reachable hosts — this is the first half of an SSRF guard (hostname scope), complemented by IP resolution checks in resolveSafeAddress.

Source

Thrown at packages/core/src/providers/manifest-service.ts:235

  }
  validateRemoteHostname(url.hostname, label);
  await resolveSafeAddress(url.hostname);
}

function validateRemoteHostname(hostname: string, label: string): void {
  const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
  if (!normalized) {
    throw new Error(`${label} is invalid.`);
  }
  if (
    normalized === "localhost" ||
    normalized.endsWith(".localhost") ||
    normalized.endsWith(".home") ||
    normalized.endsWith(".lan") ||
    normalized.endsWith(".local") ||
    normalized.endsWith(".internal")
  ) {
    throw new Error(`${label} cannot target a local or internal host.`);
  }
}

async function resolveSafeAddress(hostname: string): Promise<SafeAddress> {
  const addresses = await lookup(hostname, { all: true, verbatim: true });
  if (addresses.length === 0) {
    throw new Error(`Could not resolve host: ${hostname}`);
  }

  for (const address of addresses) {
    if (!isPublicIpAddress(address.address)) {
      throw new Error(`Remote manifest host resolved to a private or reserved address: ${address.address}`);
    }
  }

  const first = addresses[0];
  return {
    address: first.address,

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Point the manifest at the public DNS name of the service
  2. Expose the internal service through a public HTTPS endpoint (reverse proxy) if it must be referenced remotely
  3. Use a local manifest file for internal/lab targets instead of a remote manifest

Example fix

// before
"baseUrl": "https://inference.internal:8080"
// after
"baseUrl": "https://inference.example.com"
Defensive patterns

Strategy: validation

Validate before calling

const BANNED = [/^localhost$/i, /\.localhost$/i, /\.(home|lan|local|internal)$/i];
if (BANNED.some(r => r.test(hostname))) throw new Error('internal host not allowed');

Prevention

When it happens

Trigger: A manifest URL with hostname 'localhost', 'mybox.lan', 'printer.local', 'service.internal', or anything ending in '.localhost'.

Common situations: Developer points a 'remote' manifest at an internal service for testing; homelab DNS suffixes (.lan/.home) reused in production manifests; mDNS-style .local names in docs copied into config.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/9326381b6a26f983. Report an issue: GitHub.