{"record":{"id":"0502e1016eee0682","repo":"abhigyanpatwari/GitNexus","slug":"invalid-url-0502e1","errorCode":null,"errorMessage":"Invalid URL","messagePattern":"Invalid URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/net/url-guard.ts","lineNumber":21,"sourceCode":"// Cloud metadata hostnames that must never be reachable via user-supplied URLs\nconst BLOCKED_HOSTNAMES = new Set([\n  'localhost',\n  'metadata.google.internal',\n  'metadata.azure.com',\n  'metadata.internal',\n]);\n\n/**\n * Validate an outbound http(s) URL to prevent SSRF.\n * Only allows https:// and http:// schemes. Blocks private/internal addresses,\n * IPv6 private ranges, cloud metadata hostnames, and numeric IP encodings.\n */\nexport function validateGitUrl(url: string): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error('Invalid URL');\n  }\n\n  if (!['https:', 'http:'].includes(parsed.protocol)) {\n    throw new Error('Only https:// and http:// git URLs are allowed');\n  }\n\n  if (parsed.search || parsed.hash) {\n    throw new Error('Git URLs must not include query strings or fragments');\n  }\n\n  const host = parsed.hostname.toLowerCase();\n\n  // Block known dangerous hostnames (cloud metadata services)\n  if (BLOCKED_HOSTNAMES.has(host)) {\n    throw new Error('Cloning from private/internal addresses is not allowed');\n  }\n\n  // Strip IPv6 brackets if present (URL parser behavior varies across Node versions)","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/net/url-guard.ts#L3-L39","documentation":"validateGitUrl performs SSRF-safe validation of git URLs. First it requires the string to be parseable by the URL constructor; anything malformed throws 'Invalid URL'. The guard only accepts http(s) git URLs, so unparseable input is rejected before any protocol checks.","triggerScenarios":"Calling validateGitUrl (directly or via cloneOrPull / normalizedRegistry / sanitizedHttpUrl) with a string that new URL() cannot parse — missing scheme, spaces, scp-like syntax git@host:path, or bare hostnames.","commonSituations":"Passing a classic scp-style git remote (git@github.com:acme/api.git) which URL() treats as invalid; a typo like 'httpsgithub.com/acme' or missing '://'; copying a repo path instead of a URL; config containing a relative local path.","solutions":["Convert scp-style remotes to https form: git@github.com:acme/api.git → https://github.com/acme/api.git.","Include the scheme explicitly: prefix the value with https:// if it is missing.","Trim whitespace and re-check the URL in your browser/with `new URL()` before passing it in.","Use a local filesystem path API instead of cloneOrPull if you intend to clone from a local directory."],"exampleFix":"// before\nawait cloneOrPull('git@github.com:acme/api.git', dest);\n\n// after\nawait cloneOrPull('https://github.com/acme/api.git', dest);","handlingStrategy":"validation","validationCode":"function looksLikeHttpUrl(u: string): boolean {\n  try { const p = new URL(u); return p.protocol === 'https:' || p.protocol === 'http:'; }\n  catch { return false; }\n}","typeGuard":"const isParsableUrl = (u: string): boolean => { try { new URL(u); return true; } catch { return false; } };","tryCatchPattern":"try {\n  validateGitUrl(url);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Invalid URL') {\n    throw new Error(`not a valid URL: ${url} — include scheme, e.g. https://host/repo.git`);\n  }\n  throw err;\n}","preventionTips":["Normalize scp-style remotes to https before calling.","Trim and scheme-check URLs at config-load time.","Test every configured URL with new URL() in a startup check."],"tags":["url","validation","git","ssrf-guard"],"backgroundTag":"invalid-url-format","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-09-08T00:40:44.970Z","contentChangedAt":"2026-09-08T00:40:44.970Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}