{"record":{"id":"6dc8467c8706dc33","repo":"abhigyanpatwari/GitNexus","slug":"invalid-repository-name","errorCode":null,"errorMessage":"Invalid repository name","messagePattern":"Invalid repository name","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/server/git-clone.ts","lineNumber":60,"sourceCode":"  const name = parseRepoNameFromUrl(url);\n  if (\n    !name ||\n    name === '.' ||\n    name === '..' ||\n    name === 'unknown' ||\n    !REPO_NAME_PATTERN.test(name)\n  ) {\n    throw new Error('Could not extract a valid repository name from URL');\n  }\n  return name;\n}\n\n/** Get the clone target directory for a repo name. */\nexport function getCloneDir(repoName: string): string {\n  // Re-validate at the boundary even though extractRepoName already checked —\n  // callers may pass a repoName from another source (test fixtures, scripts).\n  if (!repoName || repoName === '.' || repoName === '..' || !REPO_NAME_PATTERN.test(repoName)) {\n    throw new Error('Invalid repository name');\n  }\n  return path.join(CLONE_ROOT, repoName);\n}\n\n// 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 a git URL to prevent SSRF attacks.\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 {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/git-clone.ts#L42-L78","documentation":"getCloneDir re-validates its repoName argument at the boundary — callers may pass names from test fixtures, scripts, or other sources that never went through extractRepoName. Any name failing REPO_NAME_PATTERN ^[a-zA-Z0-9._-]+$, or '.'/'..'/empty, throws before path.join(CLONE_ROOT, repoName), so the result can never escape the clone root.","triggerScenarios":"Directly calling getCloneDir('my repo'), getCloneDir('foo/bar'), getCloneDir('../escape'), or getCloneDir('') from a script/test/fixture instead of deriving the name via extractRepoName.","commonSituations":"Test fixtures inventing repo names with spaces or slashes; scripts passing user-typed display names straight through; refactors that route names around the validated extractor.","solutions":["Derive names with extractRepoName(url) (or sanitizeRepoName) before calling getCloneDir","Restrict inputs to [A-Za-z0-9._-] and strip/reject everything else","Import the exported REPO_NAME_PATTERN for shared validation"],"exampleFix":"// before\nconst dir = getCloneDir(userTypedName); // 'my repo' -> throws\n\n// after\nimport { REPO_NAME_PATTERN } from '../server/git-clone.js';\nconst safe = REPO_NAME_PATTERN.test(userTypedName) ? userTypedName : sanitizeRepoName(userTypedName);\nconst dir = getCloneDir(safe);","handlingStrategy":"type-guard","validationCode":"import { REPO_NAME_PATTERN } from './git-clone.js';\nfunction assertSafeRepoName(name) {\n  if (!REPO_NAME_PATTERN.test(name) || name === '.' || name === '..') {\n    throw new Error(`Invalid repository name: ${JSON.stringify(name)}`);\n  }\n}","typeGuard":"import { REPO_NAME_PATTERN } from './git-clone.js';\nfunction isSafeRepoName(name) {\n  return typeof name === 'string' && name.length > 0 && name !== '.' && name !== '..' && REPO_NAME_PATTERN.test(name);\n}\n// narrow before use: if (isSafeRepoName(n)) dir = getCloneDir(n);","tryCatchPattern":"try { return getCloneDir(repoName); }\ncatch (e) {\n  if (e.message === 'Invalid repository name') return getCloneDir(sanitizeRepoName(repoName)); // one repair attempt\n  throw e;\n}","preventionTips":["Never pass raw user strings to getCloneDir — derive via extractRepoName/sanitizeRepoName","Reuse the exported REPO_NAME_PATTERN for shared validation instead of re-implementing it","In tests, generate fixture names from the safe charset"],"tags":["git-clone","path-validation","path-traversal-guard","filesystem"],"backgroundTag":"invalid-repository-name","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}