{"record":{"id":"9e1d55d88d7eed0b","repo":"google-gemini/gemini-cli","slug":"invalid-oauth-endpoint-protocol-parsed-protocol","errorCode":null,"errorMessage":"Invalid OAuth endpoint protocol \"${parsed.protocol}\". Only HTTPS (and HTTP for local development) is supported.","messagePattern":"Invalid OAuth endpoint protocol \"(.+?)\"\\. Only HTTPS \\(and HTTP for local development\\) is supported\\.","errorType":"exception","errorClass":"OAuthSecurityError","httpStatus":null,"severity":"error","filePath":"packages/core/src/mcp/oauth-utils.ts","lineNumber":89,"sourceCode":"      throw new OAuthSecurityError(\n        `Failed to resolve relative OAuth URL \"${urlStr}\" against base \"${options.baseUri}\": ${getErrorMessage(e)}`,\n      );\n    }\n  }\n\n  let parsed: URL;\n  try {\n    parsed = new URL(resolvedUrl);\n  } catch (e) {\n    throw new OAuthSecurityError(\n      `Invalid OAuth endpoint URL \"${resolvedUrl}\": ${getErrorMessage(e)}`,\n    );\n  }\n\n  const isHttp = parsed.protocol === 'http:';\n  const isHttps = parsed.protocol === 'https:';\n  if (!isHttp && !isHttps) {\n    throw new OAuthSecurityError(\n      `Invalid OAuth endpoint protocol \"${parsed.protocol}\". Only HTTPS (and HTTP for local development) is supported.`,\n    );\n  }\n\n  const hostname = sanitizeHostname(parsed.hostname);\n  const isLoopback = isLoopbackHost(hostname);\n\n  if (isHttp && (!options?.allowLoopback || !isLoopback)) {\n    throw new OAuthSecurityError(\n      `Insecure HTTP OAuth endpoint \"${resolvedUrl}\" is not allowed. OAuth endpoints must use HTTPS unless connecting to localhost.`,\n    );\n  }\n\n  if (options?.expectedOrigin) {\n    let expected: string;\n    try {\n      expected = new URL(options.expectedOrigin).origin;\n    } catch {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/3c311beac2e78336816dd4a123db39743f9fbf85/packages/core/src/mcp/oauth-utils.ts#L71-L107","documentation":"The OAuth endpoint URL parsed successfully but its protocol is neither http: nor https:. The library only permits HTTP(S) for OAuth endpoints, so schemes like ftp:, file:, ws:, or javascript: are rejected before any network activity. This is an SSRF/abuse guard as much as a validation check.","triggerScenarios":"Passing URLs such as 'file:///etc/passwd', 'ftp://host/authorize', 'ws://host/oauth', or any URL whose scheme is not http/https to validateOAuthEndpointUrl.","commonSituations":"Mistyped or injected configuration values; dynamically constructed URLs where the scheme variable defaults to something unexpected; server metadata advertising an endpoint with a non-HTTP scheme; test fixtures using file:// or data:// URLs.","solutions":["Change the endpoint URL to use https:// (or http:// only for local loopback development)","Audit where the URL string is built — often a scheme variable or template placeholder is wrong","If the value came from server-discovered metadata, the remote server is advertising a broken endpoint; fix it server-side or override the endpoint in configuration"],"exampleFix":"// before\nawait validateOAuthEndpointUrl(`${proto}://auth.example.com/authorize`); // proto === 'ws'\n\n// after\nawait validateOAuthEndpointUrl(`https://auth.example.com/authorize`);","handlingStrategy":"validation","validationCode":"const ALLOWED = new Set(['http:', 'https:']);\nfunction hasAllowedScheme(v: string): boolean {\n  try { return ALLOWED.has(new URL(v).protocol); } catch { return false; }\n}\n\nif (!hasAllowedScheme(endpoint)) throw new Error(`Refusing non-HTTP(S) endpoint: ${endpoint}`);","typeGuard":"function isHttpSchemeUrl(v: string): v is `${'http'|'https'}://${string}` {\n  try { const u = new URL(v); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  await validateOAuthEndpointUrl(endpoint);\n} catch (e) {\n  if (e instanceof OAuthSecurityError && e.message.includes('Invalid OAuth endpoint protocol')) {\n    // the scheme is wrong (ftp/ws/file/...); rebuild the URL with https://\n  }\n  throw e;\n}","preventionTips":["Never build endpoint URLs by string-concatenating a configurable scheme variable","Reject non-http(s) schemes at config load time","Treat file:// or data:// endpoints in metadata as tampering and investigate"],"tags":["oauth","protocol-validation","ssrf-protection","url-parsing"],"backgroundTag":"unsupported-url-scheme","analyzedSha":"3c311beac2e78336816dd4a123db39743f9fbf85","analyzedAt":"2026-08-27T19:07:12.298Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}