{"record":{"id":"75996220c63ff3df","repo":"FlowiseAI/Flowise","slug":"invalid-file-path-null-byte-detected-in-key","errorCode":null,"errorMessage":"Invalid file path: null byte detected in \"${key}\"","messagePattern":"Invalid file path: null byte detected in \"(.+?)\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/components/src/validator.ts","lineNumber":457,"sourceCode":" * @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\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":439,"sourceCodeEnd":474,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/validator.ts#L439-L474","documentation":"Thrown by getSafeFilePath() after percent-decoding the key, when the decoded value contains a NUL byte (\\0). Null-byte injection is a classic technique to truncate a path or filename at the OS/C level so that a check sees one value but the syscall uses another; getSafeFilePath decodes first (so encoded %00 is caught too) and rejects the request outright rather than attempting to clean it.","triggerScenarios":"A key containing a literal \\0; a key containing `%00` which decodes to \\0 via decodeURIComponent; a key like `legit.txt%00.exe` intended to bypass extension checks. Reached when a client (or an attacker) supplies a URL-encoded null byte in a path/query param that flows into getSafeFilePath.","commonSituations":"Security scanning / fuzzing of file endpoints; legacy clients that include binary data in keys; a proxy that double-encodes the path. This is almost always indicative of a malicious or malformed request, not a normal user error.","solutions":["Treat the request as malicious: reject with 400 and log the source IP / request id for investigation.","Ensure the key never carries binary/null data by validating the input charset (printable ASCII / UTF-8) at the request boundary.","Do not attempt to strip the null byte and continue — the presence itself indicates an attack; reject the whole request."],"exampleFix":"// before\nconst abs = getSafeFilePath(baseDir, key) // throws on %00\n\n// after\nif (key.includes('\\0') || /%00/i.test(key)) {\n    logger.warn('Null-byte injection attempt blocked', { key, ip: req.ip })\n    return res.status(400).json({ message: 'Invalid key' })\n}\nconst abs = getSafeFilePath(baseDir, key)","handlingStrategy":"validation","validationCode":"// Reject null bytes in either raw or encoded form before resolving\nif (typeof key !== 'string' || key.includes('\\0') || /%00/i.test(key)) {\n    logger.warn('Null-byte key blocked', { key, ip: req.ip })\n    return res.status(400).json({ message: 'Invalid key' })\n}","typeGuard":"const hasNoNullByte = (v: unknown): v is string =>\n    typeof v === 'string' && !v.includes('\\0') && !/%00/i.test(v)","tryCatchPattern":"try {\n    const abs = getSafeFilePath(baseDir, key)\n} catch (e) {\n    // null-byte presence is an attack — reject and log, never strip-and-retry\n    return res.status(400).json({ message: 'Invalid file path' })\n}","preventionTips":["Validate input charset (printable UTF-8) at the trust boundary.","Treat any null byte as malicious and log the request origin.","Never strip null bytes and continue — reject the whole request."],"tags":["security","null-byte-injection","path-traversal","input-validation"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}