{"record":{"id":"95eb3d1b4b80779c","repo":"google-gemini/gemini-cli","slug":"access-to-blocked-or-private-host-url-is-not-allowed","errorCode":null,"errorMessage":"Access to blocked or private host ${url} is not allowed.","messagePattern":"Access to blocked or private host (.+?) is not allowed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/tools/web-fetch.ts","lineNumber":296,"sourceCode":"        hostname.endsWith('.local') ||\n        hostname.endsWith('.internal')\n      ) {\n        return true;\n      }\n      return await isPrivateIp(urlStr);\n    } catch {\n      return true;\n    }\n  }\n\n  private async executeFallbackForUrl(\n    urlStr: string,\n    signal: AbortSignal,\n  ): Promise<string> {\n    const url = convertGithubUrlToRaw(urlStr);\n    if (await this.isBlockedHost(url)) {\n      debugLogger.warn(`[WebFetchTool] Blocked access to host: ${url}`);\n      throw new Error(\n        `Access to blocked or private host ${url} is not allowed.`,\n      );\n    }\n\n    const response = await retryWithBackoff(\n      async () => {\n        const res = await fetchWithTimeout(url, URL_FETCH_TIMEOUT_MS, {\n          signal,\n          headers: {\n            'User-Agent': USER_AGENT,\n          },\n        });\n        if (!res.ok) {\n          const error = new Error(\n            `Request failed with status code ${res.status} ${res.statusText}`,\n          );\n          (error as ErrorWithStatus).status = res.status;\n          throw error;","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/6a466a7e2fe2b1255752c1e74f69b31f0216084d/packages/core/src/tools/web-fetch.ts#L278-L314","documentation":"WebFetchTool's fallback fetch path converts GitHub URLs to raw URLs and then checks the host with isBlockedHost. If the host is blocked (private ranges, loopback, or a user-configured deny list), the tool refuses to fetch and throws, preventing SSRF and honoring privacy/block rules.","triggerScenarios":"executeFallbackForUrl (called by content) invoked with a URL whose host isBlockedHost classifies as blocked or private, e.g. http://localhost/..., http://127.0.0.1/..., 10.x/192.168.x hosts, or hosts on the user's blocklist.","commonSituations":"The model or user asks to fetch an internal dashboard or localhost dev server; a redirect or rewritten URL lands on a private host; corporate-internal documentation URLs are requested.","solutions":["Fetch a publicly reachable URL instead of a private/loopback address.","If the host is on your configured blocklist and is intentionally allowed, remove it from the block/deny configuration (mind the security implications).","For GitHub content, ensure the URL is a public repo so the raw.githubusercontent.com conversion resolves to a public host."],"exampleFix":"// before\nWebFetch url=\"http://localhost:3000/api/status\"\n// after\nWebFetch url=\"https://status.example.com/api/status\"","handlingStrategy":"try-catch","validationCode":"const u = new URL(url);\nconst { lookup } = require('dns').promises;\nconst addrs = await lookup(u.hostname, { all: true });\nif (addrs.some(a => /^(127\\.|10\\.|192\\.168\\.|172\\.(1[6-9]|2\\d|3[01])\\.|169\\.254\\.)/.test(a.address))) {\n  throw new Error('refusing to fetch a private/loopback host');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const text = await tool.executeFallbackForUrl(urlStr, signal);\n} catch (e) {\n  if (e.message.startsWith('Access to blocked or private host')) {\n    // choose a public URL or adjust the allow/deny configuration deliberately\n  }\n}","preventionTips":["Only request publicly reachable URLs from the web-fetch tool.","Keep blocklists intentional; document any private hosts you must access and use a different mechanism for them.","Remember GitHub web URLs are rewritten to raw.githubusercontent.com — the raw host must be publicly accessible."],"tags":["network","security","ssrf","web-fetch"],"backgroundTag":"private-ip-blocked","analyzedSha":"6a466a7e2fe2b1255752c1e74f69b31f0216084d","analyzedAt":"2026-09-16T18:14:43.978Z","contentChangedAt":"2026-09-16T18:14:43.978Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}