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 operationsView on GitHub (pinned to abe4a8601a)
Solutions
- Confirm the filename extension matches the actual file content and re-upload with the correct pair.
- If the mismatch is benign (alias), extend extractFileExtension's normalization map (e.g. htm→html) so legitimate pairs pass.
- For genuine spoofing, block and log the attempt; do not relax the check globally.
- 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
- Have clients derive MIME from real content (file-type sniffing) instead of hardcoding.
- Extend extractFileExtension's alias map for legitimate extension variants (htm→html, jpeg→jpg).
- Treat genuine mismatches as security events; log and block, never relax globally.
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
- Invalid filename: unsafe characters or path traversal attemp
- Invalid MIME type: MIME type is required and must be a strin
- File type not allowed: files must have a valid file extensio
- MIME type "${mimetype}" is not supported or does not have a
- Invalid filename: filename is required and must be a string
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/0e2ebd2e9e5a8b5e.
Report an issue: GitHub.