google-gemini/gemini-cli · error · OAuthSecurityError

Failed to resolve hostname "${hostname}" for OAuth endpoint

Error message

Failed to resolve hostname "${hostname}" for OAuth endpoint "${resolvedUrl}".

What it means

For non-loopback hosts, the library performs DNS resolution (lookup with { all: true }) as an SSRF/DNS-rebinding defense, and the lookup returned no addresses (empty array). The hostname is syntactically fine but resolves to nothing at validation time.

Source

Thrown at packages/core/src/mcp/oauth-utils.ts:139

      throw new OAuthSecurityError(
        `Loopback OAuth endpoint "${resolvedUrl}" is not allowed for remote MCP servers.`,
      );
    }
    return parsed.toString();
  }

  // Non-loopback host: check literal IP
  if (isAddressPrivate(hostname)) {
    throw new OAuthSecurityError(
      `OAuth endpoint "${resolvedUrl}" points to private or reserved IP address which is blocked.`,
    );
  }

  // Asynchronous DNS resolution to prevent DNS rebinding / SSRF
  try {
    const addresses = await lookup(hostname, { all: true });
    if (!addresses || addresses.length === 0) {
      throw new OAuthSecurityError(
        `Failed to resolve hostname "${hostname}" for OAuth endpoint "${resolvedUrl}".`,
      );
    }

    for (const addr of addresses) {
      if (isAddressPrivate(addr.address)) {
        throw new OAuthSecurityError(
          `OAuth endpoint "${resolvedUrl}" resolves to private network address "${addr.address}" which is blocked.`,
        );
      }
    }
  } catch (error) {
    if (error instanceof OAuthSecurityError) {
      throw error;
    }
    throw new OAuthSecurityError(
      `DNS lookup failed for OAuth endpoint host "${hostname}": ${getErrorMessage(error)}`,
    );

View on GitHub (pinned to 3c311beac2)

Solutions

  1. Verify the hostname resolves from this environment: 'nslookup <hostname>' or 'node -e "require('dns').lookup(process.argv[1],{all:true},console.log)"'
  2. Fix typos in the configured OAuth endpoint hostname
  3. If using an internal DNS name, ensure the process's resolver can reach that DNS server (VPN, /etc/resolv.conf, Node's dns.setDefaultResultOrder caveats)
  4. Retry after DNS propagation or resolver recovery — this check is environment- and time-dependent

Example fix

// before
await validateOAuthEndpointUrl('https://auth.exmaple.com/authorize'); // typo'd domain, NXDOMAIN

// after
await validateOAuthEndpointUrl('https://auth.example.com/authorize');
Defensive patterns

Strategy: retry

Validate before calling

import { lookup } from 'node:dns/promises';

async function resolvesToAddresses(host: string): Promise<boolean> {
  try { const a = await lookup(host, { all: true }); return a.length > 0; } catch { return false; }
}

if (!(await resolvesToAddresses(new URL(endpoint).hostname))) {
  throw new Error(`Hostname does not resolve: ${endpoint}`);
}

Type guard

async function isResolvableHost(host: string): Promise<boolean> {
  try { return (await lookup(host, { all: true })).length > 0; } catch { return false; }
}

Try / catch

try {
  await validateOAuthEndpointUrl(endpoint);
} catch (e) {
  if (e instanceof OAuthSecurityError && e.message.includes('Failed to resolve hostname')) {
    // DNS returned no records: check typos/propagation/resolver, then retry after a delay
  }
  throw e;
}

Prevention

When it happens

Trigger: validateOAuthEndpointUrl called with a hostname that DNS cannot resolve to any A/AAAA record — e.g. a typo'd domain, a not-yet-propagated record, an internal DNS name unknown to the resolver, or a temporarily failing resolver returning an empty result.

Common situations: Newly deployed OAuth hosts whose DNS records haven't propagated; corporate/internal DNS names resolved from outside the network; transient DNS flakiness in CI; air-gapped environments where public DNS is unavailable.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@3c311beac2 (2026-08-27). Data as JSON: /api/errors/b9a444fb03af55f6. Report an issue: GitHub.