{"record":{"id":"07c0cfd460cd1625","repo":"abhigyanpatwari/GitNexus","slug":"backend-url-must-use-http-or-https-got-pa","errorCode":null,"errorMessage":"Backend URL must use http:// or https:// (got ${parsed.protocol})","messagePattern":"Backend URL must use http:// or https:// \\(got (.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus-web/src/services/backend-client.ts","lineNumber":304,"sourceCode":"/**\n * Validate that a backend URL is a safe http:// or https:// origin before\n * storing it as the fetch target base (CodeQL js/client-side-request-forgery).\n *\n * Throws if the URL uses a non-HTTP scheme (e.g. javascript:, data:, file://).\n * All other well-formed http/https URLs are accepted — the client intentionally\n * supports connecting to remote GitNexus servers, not just localhost.\n */\nexport function validateBackendUrl(url: string): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    // Do not echo raw input — it may contain credentials.\n    throw new Error('Invalid backend URL: must be a well-formed http:// or https:// URL');\n  }\n  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n    // Use parsed.protocol only (scheme), not the full URL, to avoid leaking credentials.\n    throw new Error(`Backend URL must use http:// or https:// (got ${parsed.protocol})`);\n  }\n}\n\nexport const setBackendUrl = (url: string): void => {\n  const trimmed = url.replace(/\\/$/, '');\n  validateBackendUrl(trimmed);\n  _backendUrl = trimmed;\n};\n\nexport const getBackendUrl = (): string => _backendUrl;\n\n/**\n * Normalize a user-entered server URL into a base URL suitable for setBackendUrl().\n * Adds protocol if missing, strips trailing slashes, and strips a trailing /api suffix\n * (since all API methods append their own /api/... paths to _backendUrl).\n */\nexport function normalizeServerUrl(input: string): string {\n  let url = input.trim().replace(/\\/+$/, '');","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus-web/src/services/backend-client.ts#L286-L322","documentation":"Thrown by validateBackendUrl() when the URL parses successfully but uses a protocol other than http: or https: (e.g. javascript:, data:, file:, ftp:). This is a CodeQL js/client-side-request-forgery guard: only the scheme is echoed in the message (parsed.protocol), never the full URL, to avoid leaking embedded credentials. The client intentionally accepts any well-formed http/https origin, including remote hosts — localhost is not required.","triggerScenarios":"Calling setBackendUrl(url)/validateBackendUrl(url) where url is 'javascript:alert(1)', 'data:text/html,...', 'file:///etc/passwd', 'ftp://host', etc. The URL constructor succeeds but protocol check fails.","commonSituations":"A malicious or malformed input reached the backend URL field (XSS attempt via javascript:); a file:// path pasted by mistake; a test fixture using a non-http scheme; an attacker probing the client-side request surface.","solutions":["Use only http:// or https:// URLs for the backend","For local development use 'http://localhost:4747' (or 'http://127.0.0.1:4747')","Reject user-supplied URLs that aren't http/https at the input layer before they reach setBackendUrl","If connecting to a remote GitNexus server, use its https:// origin"],"exampleFix":"// before — non-http scheme\nsetBackendUrl('file:///srv/gitnexus'); // throws '...must use http:// or https://...'\n\n// after — valid http(s) URL\nsetBackendUrl('http://localhost:4747');","handlingStrategy":"validation","validationCode":"function isSafeHttpUrl(url: string): boolean {\n  let parsed: URL;\n  try { parsed = new URL(url); } catch { return false; }\n  return parsed.protocol === 'http:' || parsed.protocol === 'https:';\n}\nif (!isSafeHttpUrl(input)) {\n  throw new Error('Backend URL must be http:// or https://');\n}","typeGuard":"function isHttpUrl(s: string): boolean {\n  try { const u = new URL(s); return u.protocol === 'http:' || u.protocol === 'https:'; }\n  catch { return false; }\n}","tryCatchPattern":"try {\n  setBackendUrl(input);\n} catch (e) {\n  if (e instanceof Error && /must use http:// or https:///.test(e.message)) {\n    // non-http scheme (javascript:, data:, file:) — reject at the input layer\n    showUserError('Only http:// or https:// backend URLs are allowed');\n  }\n  throw e;\n}","preventionTips":["Reject non-http(s) schemes at the input field — never let javascript:/data:/file: reach setBackendUrl","The check exists for CodeQL js/client-side-request-forgery — don't bypass it","Only the scheme is echoed in the error (not the full URL) to protect embedded credentials","For local dev, always use http://localhost:4747 or http://127.0.0.1:4747"],"tags":["validation","url","security","ssrf","config"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}