google-gemini/gemini-cli · error · Error

Private IP addresses are not allowed for the extension…

Error message

Private IP addresses are not allowed for the extension registry.

What it means

ExtensionRegistryClient guards against SSRF by checking the registry URI with isPrivateIp before fetching. If the registry URL resolves to a private/loopback IP (127.0.0.1, 10.x, 192.168.x, etc.), the client refuses to contact it. This prevents fetching extension lists from internal network hosts.

Solutions

  1. Set the registry URI to a public, internet-reachable HTTPS endpoint.
  2. If you intentionally need a local registry, use an officially supported way to allow it (e.g. a file:// or local-path registry variant if provided) rather than an http URL to a private IP.
  3. Verify with nslookup/dig what the registry hostname resolves to; switch DNS to a public resolution.

Example fix

// before (settings.json)
{ "extension": { "registry": "http://192.168.1.10/registry.json" } }
// after
{ "extension": { "registry": "https://registry.example.com/extensions.json" } }
Defensive patterns

Strategy: validation

Validate before calling

const { hostname } = new URL(registryUri);
const { lookup } = require('dns').promises;
const addrs = await lookup(hostname, { all: true });
const isPrivate = addrs.some(a =>
  /^(10\.|127\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|169\.254\.|::1$|fc00:)/i.test(a.address));
if (isPrivate) throw new Error('registry resolves to a private IP');

Try / catch

try {
  await registryClient.allExtensions();
} catch (e) {
  if (e.message.includes('Private IP addresses')) {
    // prompt user to use a public registry or approved local path registry
  }
}

Prevention

When it happens

Trigger: fetchAllExtensions (invoked via allExtensions) with a registryURI starting with 'http' whose host is or resolves to a private, loopback, or link-local IP address.

Common situations: Pointing the extension registry setting at a local mirror (localhost or LAN IP), a corporate proxy address, or a hostname that resolves to an internal IP via /etc/hosts.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@6a466a7e2f (2026-09-16). Data as JSON: /api/errors/73850883b4f204b5. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/config/extensionRegistryClient.ts:116

    return results.map((r) => r.item);
  }

  async getExtension(id: string): Promise<RegistryExtension | undefined> {
    const allExtensions = await this.fetchAllExtensions();
    return allExtensions.find((ext) => ext.id === id);
  }

  private async fetchAllExtensions(): Promise<RegistryExtension[]> {
    if (ExtensionRegistryClient.fetchPromise) {
      return ExtensionRegistryClient.fetchPromise;
    }

    const uri = this.registryURI;
    ExtensionRegistryClient.fetchPromise = (async () => {
      try {
        if (uri.startsWith('http')) {
          if (await isPrivateIp(uri)) {
            throw new Error(
              'Private IP addresses are not allowed for the extension registry.',
            );
          }
          const response = await fetchWithTimeout(
            uri,
            ExtensionRegistryClient.FETCH_TIMEOUT_MS,
          );
          if (!response.ok) {
            throw new Error(
              `Failed to fetch extensions: ${response.statusText}`,
            );
          }

          // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
          return (await response.json()) as RegistryExtension[];
        } else {
          // Handle local file path
          const filePath = resolveToRealPath(uri);

View on GitHub (pinned to 6a466a7e2f)