{"record":{"id":"749f16c74f6d2b71","repo":"FlowiseAI/Flowise","slug":"invalid-file-path-path-traversal-attempt-detected","errorCode":null,"errorMessage":"Invalid file path: path traversal attempt detected in \"${key}\"","messagePattern":"Invalid file path: path traversal attempt detected in \"(.+?)\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/components/src/validator.ts","lineNumber":469,"sourceCode":"        decodedKey = decodeURIComponent(key)\n    } catch {\n        // malformed percent-encoding — keep the raw key; resolve/relative handle it safely\n    }\n\n    if (decodedKey.includes('\\0')) {\n        throw new Error(`Invalid file path: null byte detected in \"${key}\"`)\n    }\n\n    const resolvedBase = path.resolve(baseDir)\n    const resolvedPath = path.resolve(resolvedBase, decodedKey)\n\n    if (process.env.PATH_TRAVERSAL_SAFETY === 'false') {\n        return resolvedPath\n    }\n\n    const relative = path.relative(resolvedBase, resolvedPath)\n    if (relative === '' || relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {\n        throw new Error(`Invalid file path: path traversal attempt detected in \"${key}\"`)\n    }\n\n    return resolvedPath\n}\n","sourceCodeStart":451,"sourceCodeEnd":474,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/validator.ts#L451-L474","documentation":"Thrown by getSafeFilePath() as the final containment guard: after resolving both baseDir and the key-joined path to absolute form, it computes path.relative(resolvedBase, resolvedPath) and rejects when that relative is '', '..', starts with '..'+sep, or is absolute. This catches any key that escapes baseDir via traversal sequences (`../`), symlinks resolving outside, absolute overrides, or a key that points at the baseDir root itself. The check is bypassed only if PATH_TRAVERSAL_SAFETY==='false', which must never be set in production.","triggerScenarios":"A key like `../../etc/passwd`; a key like `/etc/passwd` (absolute, escapes via override); a key that resolves to baseDir itself (relative === ''); encoded traversal `%2e%2e%2f` that decodes to `../`; a key referencing a symlinked target outside baseDir after resolution.","commonSituations":"Penetration testing; a buggy client that builds keys by concatenating user folders with relative paths; a multi-tenant storage layout where tenantId is missing and the key resolves to the shared root; misconfigured PATH_TRAVERSAL_SAFETY==='false' hiding the real escape.","solutions":["Confirm PATH_TRAVERSAL_SAFETY is NOT set to 'false' in production — that setting disables this guard entirely.","Sanitize the key to a single path segment (basename) before calling getSafeFilePath if directory structure is not required.","Investigate the offending key in logs; if it is legitimate, restructure baseDir/key so the resolved path genuinely sits beneath baseDir.","Ensure baseDir is itself a freshly created, dedicated sandbox dir (e.g. os.tmpdir() child) so escaped paths have nothing sensitive to reach."],"exampleFix":"// before\nconst abs = getSafeFilePath(workspaceDir, req.params.key) // key may contain ../\n\n// after\nconst safeKey = path.basename(req.params.key) // collapse to single segment first\nif (safeKey !== req.params.key) {\n    return res.status(400).json({ message: 'Invalid key' })\n}\nconst abs = getSafeFilePath(workspaceDir, safeKey)","handlingStrategy":"validation","validationCode":"// Collapse to a single segment first if directory structure isn't required\nconst safeKey = path.basename(key)\nif (safeKey !== key) {\n    return res.status(400).json({ message: 'Directory components are not allowed in the key' })\n}\nconst abs = getSafeFilePath(baseDir, safeKey)","typeGuard":"const isRelativeSingleSegment = (baseDir: string, v: unknown): v is string => {\n    if (typeof v !== 'string') return false\n    const rel = path.relative(path.resolve(baseDir), path.resolve(baseDir, v))\n    return rel !== '' && rel !== '..' && !rel.startsWith('..' + path.sep) && !path.isAbsolute(rel)\n}","tryCatchPattern":"try {\n    const abs = getSafeFilePath(baseDir, key)\n} catch (e) {\n    logger.warn('Path traversal blocked', { key, ip: req.ip })\n    return res.status(400).json({ message: 'Invalid file path' })\n}","preventionTips":["Never set PATH_TRAVERSAL_SAFETY=false in production; verify it is unset.","Use a dedicated sandbox baseDir per request/tenant so escaped paths reach nothing sensitive.","Collapse keys to basename upstream when nested paths aren't needed."],"tags":["security","path-traversal","containment","input-validation"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}