FlowiseAI/Flowise · critical · Error

Invalid filename: unsafe characters or path traversal attemp

Error message

Invalid filename: unsafe characters or path traversal attempt detected in filename "${filename}"

What it means

Thrown by validateFilename when isUnsafeFilePath(filename) returns true — i.e. the filename contains directory traversal (..), URL-encoded separators (%2f, %5c), null/control bytes, absolute paths, UNC paths, or extended-length path prefixes. This is the CVE path-traversal mitigation: filenames must be relative basenames.

Source

Thrown at packages/components/src/validator.ts:106

        /^[a-zA-Z]:\\/, // Absolute Windows paths (C:\)
        /^\\\\[^\\]/, // UNC paths (\\server\)
        /^\\\\\?\\/ // Extended-length paths (\\?\)
    ]

    return dangerousPatterns.some((pattern) => pattern.test(filePath))
}

/**
 * Validates filename format and security
 * @param {string} filename The filename to validate
 * @returns {void} Throws an error if validation fails
 */
const validateFilename = (filename: string): void => {
    if (!filename || typeof filename !== 'string') {
        throw new Error('Invalid filename: filename is required and must be a string')
    }
    if (isUnsafeFilePath(filename)) {
        throw new Error(`Invalid filename: unsafe characters or path traversal attempt detected in filename "${filename}"`)
    }
}

/**
 * Extracts and normalizes file extension from filename
 * @param {string} filename The filename
 * @returns {string} The normalized extension (lowercase, without dot) or empty string
 */
const extractFileExtension = (filename: string): string => {
    const filenameParts = filename.split('.')
    if (filenameParts.length <= 1) {
        return ''
    }
    let ext = filenameParts.pop()!.toLowerCase()
    // Normalize common extension variations to match MIME type mappings
    const extensionNormalizationMap: { [key: string]: string } = {
        jpeg: 'jpg', // image/jpeg and image/jpg both map to 'jpg'
        tif: 'tiff', // image/tiff and image/tif both map to 'tiff'

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Sanitize with a basename extraction (path.basename) before validation, or use the sanitize-filename library already imported.
  2. Reject the upload with a 400 and require the client to send a plain basename.
  3. Never concatenate user-supplied filenames into filesystem paths without re-validating the resolved path stays within the target dir.

Example fix

// before
validateFilename(filename) // throws on '../'

// after — coerce to a safe basename first
const safeName = path.basename(filename || '').trim()
validateFilename(safeName)
// or use the imported sanitize() for stricter cleaning
const clean = sanitize(filename || '')
validateFilename(clean)
Defensive patterns

Strategy: validation

Validate before calling

import path from 'path'
function toSafeBasename(filename: unknown): string {
  return path.basename(typeof filename === 'string' ? filename : '').trim()
}

Type guard

function isSafeBasename(filename: string): boolean {
  return filename === path.basename(filename) && !/[\\/\x00-\x1f]/.test(filename) && !filename.includes('..')
}

Try / catch

if (isUnsafeFilePath(filename)) {
  throw new Error(`Invalid filename: unsafe characters or path traversal attempt detected in filename "${filename}"`)
}

Prevention

When it happens

Trigger: Uploader sends filename='../../etc/passwd' or '..%2f..%2fconfig'; filename contains a null byte ('file.txt\0.exe'); filename is an absolute path ('/tmp/x') or Windows drive path ('C:\x'); control characters embedded in the name.

Common situations: Malicious upload attempting directory traversal; client that sends full original paths instead of basenames; URL-encoded names not decoded before validation; legacy integration that legitimately uses subpaths (now rejected by design).

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/b930b9ef72aa487f. Report an issue: GitHub.