Compare commits

...
Author SHA1 Message Date
Sonarly Claude CodeandClaude Opus 4.6 ace0f17e3c Fix file upload rejection when file-type library cannot detect content
When FileType.fromBuffer() fails to detect content from magic bytes (returns
undefined), the code was throwing an error for any file whose extension maps
to a MIME type that file-type claims to support. This blocked legitimate
uploads (e.g. JPG files with unusual headers, re-encoded images, small
thumbnails). Instead of throwing, fall back to the extension-based MIME type
which is the safe and expected behavior when content detection is inconclusive.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-19 00:42:26 +00:00
2 changed files with 22 additions and 41 deletions
@@ -122,26 +122,28 @@ describe('extractFileInfo', () => {
});
});
it('should throw error when PNG extension is used with non-PNG buffer', async () => {
await expect(
extractFileInfo({
file: textBuffer,
filename: 'fake-image.png',
}),
).rejects.toThrow(
"File content does not match its extension. The file has extension 'png' (expected mime type: image/png), but the file content could not be detected as this type. The file may be corrupted, have the wrong extension, or be a security risk.",
);
it('should fallback to extension mime type when content cannot be detected for PNG extension', async () => {
const result = await extractFileInfo({
file: textBuffer,
filename: 'fake-image.png',
});
expect(result).toEqual({
mimeType: 'image/png',
ext: 'png',
});
});
it('should throw error when PDF extension is used with non-PDF buffer', async () => {
await expect(
extractFileInfo({
file: textBuffer,
filename: 'fake-document.pdf',
}),
).rejects.toThrow(
"File content does not match its extension. The file has extension 'pdf' (expected mime type: application/pdf), but the file content could not be detected as this type. The file may be corrupted, have the wrong extension, or be a security risk.",
);
it('should fallback to extension mime type when content cannot be detected for PDF extension', async () => {
const result = await extractFileInfo({
file: textBuffer,
filename: 'fake-document.pdf',
});
expect(result).toEqual({
mimeType: 'application/pdf',
ext: 'pdf',
});
});
it('should handle markdown files using extension', async () => {
@@ -1,14 +1,8 @@
import { msg } from '@lingui/core/macro';
import { isNonEmptyString } from '@sniptt/guards';
import FileType, { type MimeType } from 'file-type';
import FileType from 'file-type';
import { lookup } from 'mrmime';
import { isDefined } from 'twenty-shared/utils';
import {
FileStorageException,
FileStorageExceptionCode,
} from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
import { buildFileInfo } from 'src/engine/core-modules/file/utils/build-file-info.utils';
export const extractFileInfo = async ({
@@ -35,22 +29,7 @@ export const extractFileInfo = async ({
let mimeType: string = 'application/octet-stream';
if (isNonEmptyString(ext)) {
const mimeTypeFromExtension = lookup(ext);
if (
mimeTypeFromExtension &&
FileType.mimeTypes.has(mimeTypeFromExtension as MimeType)
) {
throw new FileStorageException(
`File content does not match its extension. The file has extension '${ext}' (expected mime type: ${mimeTypeFromExtension}), but the file content could not be detected as this type. The file may be corrupted, have the wrong extension, or be a security risk.`,
FileStorageExceptionCode.INVALID_EXTENSION,
{
userFriendlyMessage: msg`The file extension doesn't match the file content. Please check that your file is not corrupted and has the correct extension.`,
},
);
}
mimeType = mimeTypeFromExtension ?? 'application/octet-stream';
mimeType = lookup(ext) ?? 'application/octet-stream';
}
return {