{"record":{"id":"a2619e80ff63e86c","repo":"different-ai/openwork","slug":"the-hostname-resolves-to-a-private-or-reserved-add","errorCode":null,"errorMessage":"the hostname resolves to a private or reserved address (${address})","messagePattern":"the hostname resolves to a private or reserved address \\((.+?)\\)","errorType":"exception","errorClass":"LocalManagedMcpPrivateUrlError","httpStatus":null,"severity":"error","filePath":"apps/server/src/local-managed-mcp-url-guard.ts","lineNumber":132,"sourceCode":"  return url;\n}\n\nfunction allowPrivateUrls(): boolean {\n  return process.env.OPENWORK_DEV_MODE === \"1\" || process.env.OPENWORK_ALLOW_PRIVATE_MCP_URLS === \"1\";\n}\n\ntype ResolveAddresses = (hostname: string, options: LookupAllOptions) => Promise<LookupAddress[]>;\n\nconst resolveAddresses: ResolveAddresses = (hostname, options) => lookup(hostname, options);\n\nfunction validateResolvedAddresses(hostname: string, addresses: LookupAddress[]): void {\n  if (addresses.length === 0) {\n    throw new LocalManagedMcpPrivateUrlError(`https://${hostname}/`, \"the hostname does not resolve\");\n  }\n  if (allowPrivateUrls()) return;\n  for (const { address } of addresses) {\n    if (isLocalManagedMcpPrivateAddress(address)) {\n      throw new LocalManagedMcpPrivateUrlError(\n        `https://${hostname}/`,\n        `the hostname resolves to a private or reserved address (${address})`,\n      );\n    }\n  }\n}\n\n/**\n * Resolves and validates the address inside the socket connector's lookup\n * callback. The exact validated answer is handed to net.connect, so a later\n * DNS answer cannot replace it between validation and connection.\n */\nexport function createLocalManagedMcpPublicLookup(\n  resolver: ResolveAddresses = resolveAddresses,\n): LookupFunction {\n  return (hostname, options, callback) => {\n    const lookupOptions: LookupAllOptions = { ...options, all: true, verbatim: true };\n    void resolver(hostname, lookupOptions).then((addresses) => {","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/local-managed-mcp-url-guard.ts#L114-L150","documentation":"LocalManagedMcpPrivateUrlError thrown by validateResolvedAddresses when any resolved IP for the MCP hostname is a private/reserved address (loopback, RFC1918, link-local, etc.) while private URLs are not allowed. This is an SSRF protection: remote-looking hostnames that actually resolve to internal networks are rejected. Dev can bypass via OPENWORK_DEV_MODE=1 or OPENWORK_ALLOW_PRIVATE_MCP_URLS=1.","triggerScenarios":"lookup(hostname) returns at least one address for which isLocalManagedMcpPrivateAddress(address) is true, and allowPrivateUrls() is false (neither env flag set to \"1\"). E.g. a public hostname with a DNS rebinding/hosts-file entry pointing at 127.0.0.1 or 10.x.x.x.","commonSituations":"Intentionally running an MCP server on localhost/LAN while the guard expects public URLs — needs the dev-mode env flag; /etc/hosts entries redirecting a name to 127.0.0.1; DNS rebinding protection firing on a legitimately internal service.","solutions":["If the private URL is intentional (local dev), set OPENWORK_ALLOW_PRIVATE_MCP_URLS=1 (or OPENWORK_DEV_MODE=1) for the server process","Otherwise point the config at the server's real public hostname/IP","Check /etc/hosts and DNS for entries mapping the hostname to a private address","Never disable the guard in production-facing deployments — it exists to block SSRF"],"exampleFix":"// before\n{ \"url\": \"https://my-mcp.example.com/sse\" }  // resolves to 127.0.0.1\n// after (local dev, intentional)\nOPENWORK_ALLOW_PRIVATE_MCP_URLS=1 openwork-server ...\n// or point at the public address\n{ \"url\": \"https://mcp-prod.example.com/sse\" }","handlingStrategy":"validation","validationCode":"import { lookup } from \"node:dns/promises\";\nfunction isPrivate(ip: string): boolean {\n  return ip === \"::1\" || ip.startsWith(\"127.\") || ip.startsWith(\"10.\") || ip.startsWith(\"192.168.\") || /^172\\.(1[6-9]|2\\d|3[01])\\./.test(ip) || ip.startsWith(\"169.254.\");\n}\nconst addrs = await lookup(new URL(url).hostname, { all: true });\nif (addrs.some(a => isPrivate(a.address)) && process.env.OPENWORK_ALLOW_PRIVATE_MCP_URLS !== \"1\") throw new Error(\"hostname resolves to a private address; set OPENWORK_ALLOW_PRIVATE_MCP_URLS=1 if intentional\");","typeGuard":null,"tryCatchPattern":"try {\n  await mcp.addServer({ url });\n} catch (e) {\n  if (e instanceof LocalManagedMcpPrivateUrlError && e.message.includes(\"private or reserved\")) {\n    if (isLocalDev) process.env.OPENWORK_ALLOW_PRIVATE_MCP_URLS = \"1\"; // then retry\n    else throw new Error(\"refusing internal-resolving host in production\");\n  } else throw e;\n}","preventionTips":["Set OPENWORK_ALLOW_PRIVATE_MCP_URLS=1 only in local/dev environments, never in prod","Check /etc/hosts and DNS for private-IP mappings of the hostname","Treat this error as an SSRF alarm — investigate before bypassing"],"tags":["security","ssrf","dns","mcp"],"backgroundTag":"ssrf-private-ip-blocked","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}