{"record":{"id":"9e5254026f753289","repo":"abhigyanpatwari/GitNexus","slug":"missing-path","errorCode":null,"errorMessage":"Missing path","messagePattern":"Missing path","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"gitnexus/src/server/api.ts","lineNumber":589,"sourceCode":" * containment is done inline at the readFile sink with the canonical\n * path.relative idiom for CodeQL js/path-injection recognition.\n */\nexport const handleFileRequest = async (\n  req: { query: any },\n  res: {\n    status: (code: number) => { json: (body: any) => void };\n    json: (body: any) => void;\n  },\n  repoPath: string,\n): Promise<void> => {\n  try {\n    // Type-confusion guard — req.query.path is `string | string[] | ParsedQs`.\n    // Without this, an attacker could pass `?path=a&path=b` to bypass the\n    // length-bound traversal check below (CodeQL js/type-confusion-through-\n    // parameter-tampering, same class as the /api/grep critical fix).\n    const rawFilePath = req.query.path;\n    if (rawFilePath === undefined || rawFilePath === '') {\n      res.status(400).json({ error: 'Missing path' });\n      return;\n    }\n    const filePath = assertString(rawFilePath, 'path');\n\n    // Path-injection containment — inline at the sink with the canonical\n    // path.relative idiom that CodeQL's js/path-injection sanitizer\n    // recognizes. assertSafePath in validation.ts performs the equivalent\n    // check, but cross-module helpers are not followed by CodeQL's\n    // interprocedural analysis for path-traversal sanitization in JS, so\n    // the barrier must be visible inline at the readFile sink.\n    const repoRoot = path.resolve(repoPath);\n    const fullPath = path.resolve(repoRoot, filePath);\n    const fullRel = path.relative(repoRoot, fullPath);\n    if (fullRel.startsWith('..') || path.isAbsolute(fullRel)) {\n      res.status(403).json({ error: 'Path traversal denied' });\n      return;\n    }\n","sourceCodeStart":571,"sourceCodeEnd":607,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/server/api.ts#L571-L607","documentation":"HTTP 400 from the repo file-read API when req.query.path is undefined or the empty string. The guard exists partly as a type-confusion barrier: req.query.path can be string, string[], or a parsed query object, and the empty/undefined check happens before assertString narrows it. Any request to read a repo file must therefore carry a non-empty ?path= value.","triggerScenarios":"Calling the file endpoint with no ?path query at all; sending ?path= (empty value); a client building the URL with a variable that is undefined and producing a bare query key (?path); query strings mangled by encoding so the param name does not match exactly.","commonSituations":"Frontend opening a file viewer before a file is selected (path variable still undefined); URL template typos like ?filePath= instead of ?path=; trailing '?' with the param dropped by a serializer; tests hitting the route without fixtures.","solutions":["Include a non-empty relative path: GET ?path=src/index.ts","Guard client-side before issuing the request when the selected path is null/empty (skip or disable the fetch)","URL-encode the path (encodeURIComponent) so slashes and spaces survive the query string","Use the exact param name 'path' (not filePath/p/file) as documented on the route"],"exampleFix":"// before\nfetch(`${base}/api/file?path=${selected?.path ?? ''}`); // 400 Missing path\n\n// after\nif (!selected?.path) throw new Error('select a file first');\nfetch(`${base}/api/file?path=${encodeURIComponent(selected.path)}`);","handlingStrategy":"validation","validationCode":"// Require a non-empty path before issuing the request.\nconst raw = selected?.path;\nif (typeof raw !== 'string' || raw.trim() === '') throw new Error('path query parameter is required');\nawait fetch(`${base}/api/file?path=${encodeURIComponent(raw)}`);","typeGuard":"function isNonEmptyString(v: unknown): v is string {\n  return typeof v === 'string' && v.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Disable the file-viewer fetch until a file is actually selected","Use the exact query key 'path' in URL builders","URL-encode paths so params are never dropped or split"],"tags":["http-400","query-params","validation","api"],"backgroundTag":"missing-required-parameter","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}