{"record":{"id":"3c3adab1e2ccfe37","repo":"Mintplex-Labs/anything-llm","slug":"invalid-path","errorCode":null,"errorMessage":"Invalid path.","messagePattern":"Invalid path\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"collector/utils/files/index.js","lineNumber":224,"sourceCode":" * @returns {boolean} True if `inner` is strictly inside `outer`, false otherwise.\n */\nfunction isWithin(outer, inner) {\n  const resolvedOuter = path.resolve(outer);\n  const resolvedInner = path.resolve(inner);\n  const rel = path.relative(resolvedOuter, resolvedInner);\n\n  if (rel === \"\") return false;\n  return (\n    !rel.startsWith(`..${path.sep}`) && rel !== \"..\" && !path.isAbsolute(rel)\n  );\n}\n\nfunction normalizePath(filepath = \"\") {\n  const result = path\n    .normalize(filepath.trim())\n    .replace(/^(\\.\\.(\\/|\\\\|$))+/, \"\")\n    .trim();\n  if ([\"..\", \".\", \"/\"].includes(result)) throw new Error(\"Invalid path.\");\n  return result;\n}\n\n/**\n * Strips characters that are illegal in Windows filenames, including Unicode\n * quotation marks (U+201C, U+201D, etc.) that can get corrupted into ASCII\n * double-quotes during charset conversion in the upload pipeline.\n * @param {string} fileName - The filename to sanitize.\n * @returns {string} - The sanitized filename.\n */\nfunction sanitizeFileName(fileName) {\n  if (!fileName) return fileName;\n  return fileName.replace(\n    /[<>:\"/\\\\|?*\\u201C\\u201D\\u201E\\u201F\\u2018\\u2019\\u201A\\u201B]/g,\n    \"\"\n  );\n}\n","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/collector/utils/files/index.js#L206-L242","documentation":"Thrown by `normalizePath` after it strips leading `..` segments and the remainder collapses to exactly `..`, `.`, or `/`. This is a path-traversal / root-escape guard: those three results would resolve outside or to the root of the intended directory tree, so the function refuses to return them. It complements the leading-`..` regex strip with a final shape check.","triggerScenarios":"Input like `../../../..` that normalizes to `..`; input of `..` or `.` directly; an absolute path `/` that survives normalization; a filename or override path composed entirely of traversal segments; crafted/malicious `destinationOverride` or uploaded filename attempting to escape the documents folder.","commonSituations":"User-controlled filenames or paths (uploads, destination overrides) containing traversal sequences; a sanitizer upstream strips everything except dots; security testing/probing of the upload endpoint.","solutions":["Treat this error as a security signal — investigate the source of the path input rather than silencing it.","Ensure upstream `sanitizeFileName` runs first so filenames never reach normalizePath as pure traversal strings.","Reject user-supplied `destinationOverride` values that are absolute or contain `..` before calling normalizePath.","If legitimately constructing a path, build it from trusted components via `path.join(knownRoot, safeRelative)` instead of normalizing user input.","Add a test asserting traversal inputs throw."],"exampleFix":"// before\nconst safe = normalizePath(userInput); // may throw 'Invalid path.'\n\n// after — reject traversal at the boundary, then normalize\nif (typeof userInput !== 'string' || /[\\/]|^(?:\\.\\.?)+$/.test(userInput.trim())) {\n  throw new Error('Destination must be a relative path without traversal segments');\n}\nconst safe = normalizePath(userInput);","handlingStrategy":"validation","validationCode":"function isSafeRelativePath(p) {\n  if (typeof p !== 'string') return false;\n  const s = p.trim();\n  if (s === '' || s === '.' || s === '..' || path.isAbsolute(s)) return false;\n  if (/(^|\\\\)\\.\\.?(\\\\|$)/.test(s)) return false; // any traversal segment\n  return true;\n}\n// only call normalizePath when isSafeRelativePath is true","typeGuard":"function isNormalizedSafe(result) {\n  return typeof result === 'string' && result !== '..' && result !== '.' && result !== '/';\n}","tryCatchPattern":"try {\n  const safe = normalizePath(input);\n} catch (e) {\n  if (/Invalid path/i.test(e.message)) {\n    // SECURITY: treat as malicious/malformed — reject the request, do not fall back\n    throw new Error('Rejected: path traversal is not allowed');\n  }\n  throw e;\n}","preventionTips":["Treat this throw as a security signal — never silently broaden it.","Run sanitizeFileName on user filenames before normalizePath.","Build paths from trusted roots with path.join instead of normalizing user input.","Add a test that traversal inputs throw."],"tags":["files","security","path-traversal","filesystem","validation"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}