musistudio/claude-code-router · error · Error

Remote manifest host resolved to a private or reserved addre

Error message

Remote manifest host resolved to a private or reserved address: ${address.address}

What it means

After resolving the manifest host, every returned IP is checked with isPublicIpAddress; if any resolved address is private/reserved (RFC1918, loopback, link-local, etc.) this error fires. This defeats DNS-rebinding SSRF: a public-looking hostname that resolves to an internal IP is rejected.

Source

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

    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,
    family: first.family === 6 ? 6 : 4
  };
}

function isPublicIpAddress(address: string): boolean {
  const family = net.isIP(address);
  if (family === 4) {
    return isPublicIpv4(address);
  }
  if (family === 6) {
    return isPublicIpv6(address);
  }

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Use a host whose DNS returns only public addresses (remove internal A/AAAA records from the public zone)
  2. Avoid rebinding-friendly domains (nip.io etc.) in manifests
  3. For internal targets, use a local manifest rather than a remote one
  4. Check `dig +short <host>` for the full record set from the machine running the app
Defensive patterns

Strategy: validation

Validate before calling

import { lookup } from 'node:dns/promises';
import { isPublicIpAddress } from './ip';
const addrs = await lookup(hostname, { all: true });
if (addrs.some(a => !isPublicIpAddress(a.address))) throw new Error('non-public resolution');

Prevention

When it happens

Trigger: A manifest host whose DNS A/AAAA records include 10.x, 192.168.x, 172.16-31.x, 127.x, 169.254.x, or other non-public ranges — including multi-record responses where only some records are private.

Common situations: Wildcard DNS (e.g. nip.io/sslip.io style) mapping to 127.0.0.1; a service with both public and internal A records; DNS rebinding services; split-horizon DNS returning the internal IP to your network.

Related errors


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