{"record":{"id":"0ea1548e111af89c","repo":"Hmbown/CodeWhale","slug":"mcp-http-destination-is-a-restricted-ip-address","errorCode":null,"errorMessage":"MCP HTTP destination is a restricted IP address","messagePattern":"MCP HTTP destination is a restricted IP address","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/http_client.rs","lineNumber":250,"sourceCode":"\nfn validate_url(url: &Url) -> Result<()> {\n    if !matches!(url.scheme(), \"http\" | \"https\") || url.host_str().is_none() {\n        bail!(\"MCP HTTP requires an http:// or https:// URL with a host\");\n    }\n    Ok(())\n}\n\nfn url_has_credentials(url: &Url) -> bool {\n    !url.username().is_empty() || url.password().is_some()\n}\n\nimpl McpHttpClient {\n    async fn public_dns_pin(&self, url: &Url) -> Result<Option<(String, SocketAddr)>> {\n        let host = url.host_str().context(\"MCP URL has no host\")?;\n        let literal = host.trim_start_matches('[').trim_end_matches(']');\n        if let Ok(ip) = literal.parse::<IpAddr>() {\n            if is_restricted_ip(&ip) {\n                bail!(\"MCP HTTP destination is a restricted IP address\");\n            }\n            return Ok(None);\n        }\n        let port = url.port_or_known_default().context(\"MCP URL has no port\")?;\n        #[cfg(test)]\n        let injected = self\n            .dns_answers\n            .lock()\n            .unwrap()\n            .as_mut()\n            .map(|answers| answers.pop_front().expect(\"DNS fixture answer available\"));\n        #[cfg(not(test))]\n        let injected: Option<Vec<SocketAddr>> = None;\n        let addresses: Vec<_> = if let Some(addresses) = injected {\n            addresses\n        } else {\n            tokio::time::timeout(self.connect_timeout, tokio::net::lookup_host((host, port)))\n                .await","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp/http_client.rs#L232-L268","documentation":"This error is thrown by McpHttpClient::public_dns_pin as an SSRF guard. When the MCP server URL host is a literal IP address, the client checks it against is_restricted_ip (the same guard used by the web-fetch tooling) and refuses to connect if the address is private, loopback, link-local, or otherwise restricted. It exists to stop a configured MCP endpoint from reaching internal network services.","triggerScenarios":"Calling client_for_target / public_dns_pin with an MCP server URL whose host is a literal restricted IP (e.g. http://127.0.0.1:8080, http://10.0.0.5, http://192.168.1.10, http://169.254.169.254).","commonSituations":"Developers pointing an MCP server config at a local dev server (localhost by IP), Docker-internal addresses, or a staging box on a private subnet; CI environments where the MCP server runs on 127.0.0.1.","solutions":["Expose the MCP server on a publicly resolvable DNS name (or a routable address that is not in a restricted range) and use that in the server config","If the server must stay local, run it through a tunnel (e.g. a public HTTPS endpoint) the guard permits","Check the URL in the MCP server config for a typo that turned a hostname into an IP literal","If the restriction is genuinely wrong for your deployment, change the config environment rather than bypassing the guard"],"exampleFix":"// before\n\"mcpServers\": { \"local\": { \"url\": \"http://127.0.0.1:8080/mcp\" } }\n// after\n\"mcpServers\": { \"local\": { \"url\": \"https://mcp.example.com/mcp\" } }","handlingStrategy":"validation","validationCode":"fn is_mcp_url_allowed(url: &url::Url) -> bool {\n    url.host_str()\n        .map(|h| h.parse::<std::net::IpAddr>().map(|ip| !is_restricted_ip(&ip)).unwrap_or(true))\n        .unwrap_or(false)\n}","typeGuard":"fn is_literal_restricted_ip(host: &str) -> bool {\n    host.trim_start_matches('[').trim_end_matches(']')\n        .parse::<std::net::IpAddr>()\n        .map(|ip| is_restricted_ip(&ip))\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Use DNS hostnames, not raw IP literals, in MCP server configs","Never configure loopback, RFC1918, or link-local addresses as MCP destinations","Validate server URLs at config-load time with the same is_restricted_ip check"],"tags":["ssrf","mcp","network","security"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T21:17:16.096Z"}