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
- Set the registry URI to a public, internet-reachable HTTPS endpoint.
- 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.
- 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
- Always use public HTTPS registry endpoints.
- Check DNS resolution of custom registry hostnames before configuring them.
- Never point the registry at localhost/LAN IPs in shared or production configs.
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
- Access to blocked or private host
- A2AClient cancelTask Error
- A2AClient getTask Error
- [A2AClientManager] sendMessageStream Error
- Access to forbidden path is denied
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)