fix(security): chunked-upload init checks the size cap before the type allow-list

Keeps the size error first, as before the allow-list landed, and pins the
allow-list gate in the size-limit suite: a .html filename is refused
whatever MIME the client declares.
This commit is contained in:
Paul Nothaft
2026-09-03 10:58:11 +02:00
parent 835312e8e6
commit 0ac006bb95
2 changed files with 38 additions and 16 deletions
+15 -14
View File
@@ -1626,20 +1626,6 @@ router.post('/:eventId/chunked-upload/init', adminAuth, requirePermission('photo
return res.status(400).json({ error: 'Missing required fields: filename, fileSize' });
}
// The client-declared mimeType is not trusted. It used to be stored on
// the photo row verbatim and echoed as Content-Type by the gallery
// routes, so a JPEG/HTML polyglot declared as text/html rendered inline
// on the app origin. The MIME is derived from the extension instead,
// and the extension has to be on the admin's allow-list, which is what
// the multipart path enforces through its multer fileFilter.
const ext = path.extname(String(filename)).slice(1).toLowerCase();
const mimeType = Object.prototype.hasOwnProperty.call(EXTENSION_TO_MIME, ext)
? EXTENSION_TO_MIME[ext]
: null;
const allowedMimeTypes = await getAllowedMimeTypes();
if (!mimeType || !allowedMimeTypes.includes(mimeType)) {
return res.status(400).json({ error: 'File type not allowed' });
}
// Validate file size against the configured per-file cap. Hardcoding 10GB
// here let the chunked path sidestep general_max_file_size_mb entirely.
@@ -1655,6 +1641,21 @@ router.post('/:eventId/chunked-upload/init', adminAuth, requirePermission('photo
});
}
// The client-declared mimeType is not trusted. It used to be stored on
// the photo row verbatim and echoed as Content-Type by the gallery
// routes, so a JPEG/HTML polyglot declared as text/html rendered inline
// on the app origin. The MIME is derived from the extension instead,
// and the extension has to be on the admin's allow-list, which is what
// the multipart path enforces through its multer fileFilter.
const ext = path.extname(String(filename)).slice(1).toLowerCase();
const mimeType = Object.prototype.hasOwnProperty.call(EXTENSION_TO_MIME, ext)
? EXTENSION_TO_MIME[ext]
: null;
const allowedMimeTypes = await getAllowedMimeTypes();
if (!mimeType || !allowedMimeTypes.includes(mimeType)) {
return res.status(400).json({ error: 'File type not allowed' });
}
const result = await chunkedUpload.initializeUpload({
filename,
fileSize,