FlowiseAI/Flowise · error · Error

MIME type mismatch: file extension "${normalizedExt}" does n

Error message

MIME type mismatch: file extension "${normalizedExt}" does not match declared MIME type "${mimetype}". Expected: ${expectedExt}

What it means

Thrown when the file's actual extension (normalizedExt) differs from the extension that mapMimeTypeToExt expects for the declared MIME type. This is the core CVE-2025-61687 spoofing block: e.g. a file named payload.js declaring image/png is rejected because png maps to 'png', not 'js'.

Source

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

    const normalizedExt = extractFileExtension(filename)

    if (!normalizedExt) {
        // Files without extensions are rejected for security
        throw new Error('File type not allowed: files must have a valid file extension')
    }

    // Get the expected extension from mapMimeTypeToExt (returns extension without dot)
    const expectedExt = mapMimeTypeToExt(mimetype)

    if (!expectedExt) {
        // If mapMimeTypeToExt doesn't recognize the MIME type, it's not supported
        throw new Error(`MIME type "${mimetype}" is not supported or does not have a valid file extension mapping`)
    }

    // Ensure the file extension matches the expected extension for the MIME type
    if (normalizedExt !== expectedExt) {
        throw new Error(
            `MIME type mismatch: file extension "${normalizedExt}" does not match declared MIME type "${mimetype}". Expected: ${expectedExt}`
        )
    }
}

/**
 * Filters an array of MIME type strings to only those allowed for file upload config.
 * Used when sanitizing chatbotConfig.allowedUploadFileTypes to prevent malicious values.
 * @param {string[]} mimeTypes Raw MIME types (e.g. from splitting comma-separated config)
 * @returns {string[]} Only MIME types that pass isAllowedUploadMimeType
 */
export const filterAllowedUploadMimeTypes = (mimeTypes: string[]): string[] => {
    if (!Array.isArray(mimeTypes)) return []
    return mimeTypes.map((m) => (typeof m === 'string' ? m.trim() : '')).filter((m) => m !== '' && isAllowedUploadMimeType(m))
}

/**
 * Get allowed base directories for vector store operations

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Confirm the filename extension matches the actual file content and re-upload with the correct pair.
  2. If the mismatch is benign (alias), extend extractFileExtension's normalization map (e.g. htm→html) so legitimate pairs pass.
  3. For genuine spoofing, block and log the attempt; do not relax the check globally.
  4. Ensure clients derive MIME from real content (e.g. file-type sniffing) rather than hardcoding.

Example fix

// before
if (normalizedExt !== expectedExt) {
  throw new Error(`MIME type mismatch: file extension "${normalizedExt}" does not match declared MIME type "${mimetype}". Expected: ${expectedExt}`)
}

// after — surface a clear 415 at the handler and keep validator strict
try {
  validateMimeTypeAndExtensionMatch(req.file.originalname, req.file.mimetype)
} catch (e) {
  return res.status(415).json({ error: e.message, filename: req.file.originalname, declaredMime: req.file.mimetype })
}
Defensive patterns

Strategy: validation

Validate before calling

import { mapMimeTypeToExt } from './utils'
function extensionMatchesMime(filename: string, mime: string): boolean {
  const parts = filename.split('.')
  const ext = (parts[parts.length - 1] || '').toLowerCase()
  const expected = mapMimeTypeToExt(mime.trim().toLowerCase())
  return Boolean(expected) && ext === expected
}

Type guard

function isConsistentFileMeta(filename: string, mime: string): boolean {
  const ext = (filename.split('.').pop() || '').toLowerCase()
  const expected = mapMimeTypeToExt(mime.trim().toLowerCase())
  return Boolean(expected) && ext === expected
}

Try / catch

if (!isConsistentFileMeta(filename, mimetype)) {
  throw new Error(`MIME type mismatch: file extension "${normalizedExt}" does not match declared MIME type "${mimetype}". Expected: ${expectedExt}`)
}

Prevention

When it happens

Trigger: Attacker uploads evil.js with Content-Type image/png to bypass an extension allow-list; client genuinely mislabels the type (renamed a .jpg to .png but kept image/jpeg); normalisation gap (extension 'jpg' vs expected 'jpg' should pass, but a real mismatch like 'txt' vs 'pdf' fails).

Common situations: Security control catching genuine spoofing attempts; benign mismatch from users renaming files; extension-alias edge cases not covered by the normalization map in extractFileExtension.

Related errors


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