{"record":{"id":"88ce9856a28e9001","repo":"FlowiseAI/Flowise","slug":"invalid-file-path-key-is-required-and-must-be-a-s","errorCode":null,"errorMessage":"Invalid file path: key is required and must be a string","messagePattern":"Invalid file path: key is required and must be a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/src/validator.ts","lineNumber":446,"sourceCode":"    baseName = baseName.replace(/^\\.+/, '')\n    if (!baseName || isUnsafeFilePath(baseName)) {\n        throw new Error(`Invalid or unsafe file name: ${name}`)\n    }\n    return baseName\n}\n\n/**\n * Safely resolve an untrusted relative key/filename to an absolute path inside a\n * trusted base directory, guaranteeing the result cannot escape that directory.\n *\n * @param {string} baseDir The trusted base directory (e.g. a freshly created temp dir)\n * @param {string} key The untrusted relative key or filename\n * @returns {string} A validated absolute path guaranteed to be within baseDir\n * @throws {Error} If key is missing/invalid or the resolved path escapes baseDir\n */\nexport const getSafeFilePath = (baseDir: string, key: string): string => {\n    if (!key || typeof key !== 'string') {\n        throw new Error('Invalid file path: key is required and must be a string')\n    }\n\n    let decodedKey = key\n    try {\n        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","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/validator.ts#L428-L464","documentation":"Thrown by getSafeFilePath(baseDir, key) when `key` is falsy or not a string. getSafeFilePath is the hard boundary that resolves an untrusted relative key/filename to an absolute path guaranteed to stay inside baseDir, so it refuses any key it cannot treat as text. The check happens before percent-decoding, null-byte scanning, and the path.relative containment test, so a missing key fails fast and early.","triggerScenarios":"Calling getSafeFilePath(tmpDir, undefined), getSafeFilePath(tmpDir, null), getSafeFilePath(tmpDir, ''), or getSafeFilePath(tmpDir, 0). Typically reached from a storage/attachment handler that resolves an object key from a request param, query, or DB column that was null/empty.","commonSituations":"A route handler that reads req.params.key but the client omitted it; a DB row whose storageKey column is NULL; a refactor that renamed the field and left the old accessor returning undefined; integration tests that pass an empty key.","solutions":["Validate the key at the controller boundary and return 400 before calling getSafeFilePath.","Guard with a type check: `if (typeof key !== 'string' || key.length === 0)` then reject the request.","If empty keys are semantically invalid for your flow, assert that upstream (e.g. the upload step that stores the key)."],"exampleFix":"// before\nconst abs = getSafeFilePath(baseDir, req.query.key) // req.query.key may be undefined\n\n// after\nconst key = req.query.key\nif (typeof key !== 'string' || key.length === 0) {\n    return res.status(400).json({ message: 'key is required' })\n}\nconst abs = getSafeFilePath(baseDir, key)","handlingStrategy":"validation","validationCode":"if (typeof key !== 'string' || key.length === 0) {\n    return res.status(400).json({ message: 'A non-empty key is required' })\n}\nconst abs = getSafeFilePath(baseDir, key)","typeGuard":"const isNonEmptyKey = (v: unknown): v is string =>\n    typeof v === 'string' && v.length > 0","tryCatchPattern":"try {\n    const abs = getSafeFilePath(baseDir, key)\n} catch (e) {\n    return res.status(400).json({ message: (e as Error).message })\n}","preventionTips":["Validate key presence in the controller before resolving paths.","Ensure DB columns that hold storage keys are NOT NULL.","Type route params as string and reject missing ones via schema validation."],"tags":["validation","path-traversal","security","input-validation","typescript"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}