{"record":{"id":"1a4e8abf277da2b8","repo":"abhigyanpatwari/GitNexus","slug":"llm-base-url-must-use-http-or-https-got-p","errorCode":null,"errorMessage":"LLM base URL must use http:// or https:// (got ${parsed.protocol})","messagePattern":"LLM base URL must use http:// or https:// \\(got (.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/wiki/llm-client.ts","lineNumber":252,"sourceCode":" * clear error rather than an opaque network error.\n */\nexport function validateLLMBaseUrl(\n  baseUrl: string,\n  allowedInsecureHttpHosts: readonly string[] = parseLLMAllowedInsecureHttpHosts(\n    process.env[LLM_ALLOW_INSECURE_CONNECTION_ENV],\n  ),\n): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(baseUrl);\n  } catch {\n    // Do not include the raw input in the message — it may contain credentials.\n    throw new Error('Invalid LLM base URL: must be a well-formed http:// or https:// URL');\n  }\n\n  if (!['https:', 'http:'].includes(parsed.protocol)) {\n    // Use parsed.protocol only (scheme), not the full URL, to avoid leaking credentials.\n    throw new Error(`LLM base URL must use http:// or https:// (got ${parsed.protocol})`);\n  }\n\n  if (parsed.protocol === 'http:') {\n    // Node's URL parser preserves IPv6 brackets in hostname (e.g. \"[::1]\"),\n    // so strip them before comparing to bare address literals.\n    const host = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n    const allowedHosts = new Set(allowedInsecureHttpHosts.map(normalizeAllowedInsecureHttpHost));\n    if (host !== 'localhost' && host !== '127.0.0.1' && host !== '::1' && !allowedHosts.has(host)) {\n      // Use parsed.origin (scheme+host+port, no credentials) instead of the full URL.\n      throw new Error(\n        `Insecure http:// LLM base URLs are only allowed for localhost/127.0.0.1 ` +\n          `or hosts listed by --allow-insecure-connection / ${LLM_ALLOW_INSECURE_CONNECTION_ENV}. ` +\n          `Use https:// for remote endpoints (got ${parsed.origin})`,\n      );\n    }\n  }\n}\n","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/wiki/llm-client.ts#L234-L270","documentation":"validateLLMBaseUrl successfully parsed the base URL but its protocol is neither http: nor https:. The message echoes only parsed.protocol (never the full URL) to avoid leaking embedded credentials. This guard blocks file://, data:, javascript:, ws:, ftp: and every other scheme (CWE-918 hardening), because the fetch-based LLM client must only talk to HTTP endpoints.","triggerScenarios":"Passing `--base-url file:///...`, `ws://host:8080/v1`, `ftp://...`, or a typo like `htps://` that parses to an unexpected scheme; a provider preset that accidentally produced a WebSocket URL.","commonSituations":"Pointing at a WebSocket endpoint of a self-hosted server; typo'd scheme; pasting a data: or file: URI by accident; scripts templating the scheme from a variable that is empty or 'ws'.","solutions":["Change the scheme to https:// (or http:// for localhost): `--base-url https://api.example.com/v1`","Fix the typo in the scheme (htps://, httpss://, etc.)","For local servers use `http://localhost:PORT/v1` which passes the insecure-host check automatically"],"exampleFix":"# before\ngitnexus wiki --provider custom --base-url ws://localhost:8080/v1\n\n# after\ngitnexus wiki --provider custom --base-url http://localhost:8080/v1","handlingStrategy":"validation","validationCode":"const allowed = new Set(['http:', 'https:']);\nconst proto = (() => { try { return new URL(baseUrl).protocol; } catch { return null; } })();\nif (proto && !allowed.has(proto)) throw new Error(`Unsupported scheme ${proto}; use https://`);","typeGuard":"function isHttpUrl(value: string): boolean {\n  try { return ['http:', 'https:'].includes(new URL(value).protocol); } catch { return false; }\n}","tryCatchPattern":"try {\n  validateLLMBaseUrl(baseUrl);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('LLM base URL must use http:// or https://')) {\n    // rewrite ws://→http:// or file:// rejection; fix at the config source\n  }\n}","preventionTips":["Restrict provider-config UIs/CLIs to http(s) schemes at input time","When templating URLs from variables, default the scheme to https","Unit-test config builders asserting the final protocol is http: or https:"],"tags":["llm","url-validation","scheme","security","gitnexus"],"backgroundTag":"invalid-url-scheme","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}