FlowiseAI/Flowise · critical · Error
Invalid or unsafe file name: ${name}
Error message
Invalid or unsafe file name: ${name} What it means
Thrown by sanitizeFileName() after it has stripped the FILE-STORAGE:: prefix, percent-decoded, extracted the basename via path.basename, run it through the sanitize-filename package, and removed leading dots — and the result (`baseName`) is either empty or still flagged by isUnsafeFilePath(). isUnsafeFilePath rejects any remaining `..`, encoded traversal bytes, null/control chars, absolute Unix/Windows roots, or UNC/extended-length prefixes. Reaching this throw means the input survived every normalization step yet is still dangerous, so it is treated as a malicious or corrupt file name.
Source
Thrown at packages/components/src/validator.ts:430
// Strip the FILE-STORAGE:: prefix if present
let stripped = name.replace(/^FILE-STORAGE::/, '')
// Decode percent-encoded traversal sequences before basename extraction
try {
stripped = decodeURIComponent(stripped)
} catch (_) {
// If decoding fails the raw string is fine — basename will still strip dirs
}
// Normalize backslashes to forward slashes so path.basename works on all
// platforms (on Linux, path.basename does not treat \ as a separator)
stripped = stripped.replace(/\\/g, '/')
// Extract only the base filename — removes all directory components
let baseName = path.basename(stripped)
// Run through sanitize-filename to strip OS-reserved chars, control chars, etc.
baseName = sanitize(baseName)
// Remove leading dots to prevent hidden files or relative path references
baseName = baseName.replace(/^\.+/, '')
if (!baseName || isUnsafeFilePath(baseName)) {
throw new Error(`Invalid or unsafe file name: ${name}`)
}
return baseName
}
/**
* Safely resolve an untrusted relative key/filename to an absolute path inside a
* trusted base directory, guaranteeing the result cannot escape that directory.
*
* @param {string} baseDir The trusted base directory (e.g. a freshly created temp dir)
* @param {string} key The untrusted relative key or filename
* @returns {string} A validated absolute path guaranteed to be within baseDir
* @throws {Error} If key is missing/invalid or the resolved path escapes baseDir
*/
export const getSafeFilePath = (baseDir: string, key: string): string => {
if (!key || typeof key !== 'string') {
throw new Error('Invalid file path: key is required and must be a string')
}
View on GitHub (pinned to abe4a8601a)
Solutions
- Log the offending `name` server-side to identify whether it is malicious traffic or a legitimate edge case.
- If legitimate, generate a safe replacement name (UUID) instead of forwarding the raw value, then retry the operation.
- Sanitize/normalize the input at the source (client or upstream service) so it contains only alphanumerics, dash, underscore, dot before reaching Flowise.
- Verify PATH_TRAVERSAL_SAFETY is intentionally left at its safe default ('false' disables the isUnsafeFilePath check entirely and must never be set in production).
Example fix
// before
const safe = sanitizeFileName(userSuppliedName) // throws on residual unsafe content
// after
let safe: string
try {
safe = sanitizeFileName(userSuppliedName)
} catch {
safe = crypto.randomUUID() // fall back to a guaranteed-safe name
}
logger.warn('Rejected unsafe filename; substituted generated name', { original: userSuppliedName }) Defensive patterns
Strategy: validation
Validate before calling
// Pre-screen with the same predicate the sanitizer uses
if (isUnsafeFilePath(name)) {
return res.status(400).json({ message: 'Unsafe file name' })
}
let safe: string
try {
safe = sanitizeFileName(name)
} catch {
safe = crypto.randomUUID() // or reject
} Try / catch
try {
const safe = sanitizeFileName(name)
} catch (e) {
logger.warn('sanitizeFileName rejected input', { name, err: (e as Error).message })
// do NOT strip chars and retry with the same name — treat as malicious/corrupt
return res.status(400).json({ message: 'Invalid file name' })
} Prevention
- Treat residual-unsafe as an attack signal: log and reject, don't silently clean.
- Keep PATH_TRAVERSAL_SAFETY at its safe default (unset); setting it to 'false' disables isUnsafeFilePath.
- Pre-normalize names to basename at the client/upstream so only single segments arrive.
When it happens
Trigger: A name composed entirely of reserved/control characters that sanitize-filename strips to an empty string (e.g. a name of all dots, all backslashes, or all control bytes); a name whose decoded form still contains `..` after basename extraction on a platform where separators behave unexpectedly; a deliberately crafted payload like `....//....//etc/passwd` that reduces to a traversal fragment; a name with embedded null or control characters that survive sanitization.
Common situations: Penetration testing / fuzzing of the upload API; a storage migration that reintroduces raw user-supplied names; PATH_TRAVERSAL_SAFETY left enabled (the default) while a client sends OS-reserved or encoded payloads; a filename that legitimately had only an extension with no base portion and got stripped to nothing.
Related errors
- Invalid path: null bytes or control characters detected
- Invalid SQLite path: null bytes or control characters detect
- Invalid file name: name is required
- Invalid file path: key is required and must be a string
- Invalid file path: null byte detected in "${key}"
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/b921acd678945a8d.
Report an issue: GitHub.