Safe file uploads with multer
File uploads are one of the most exploited corners of any web API. Accept a file the wrong way and you hand attackers the keys. Get it right with a handful of defensive rules and the feature is safe.
import multer from 'multer';
import path from 'path';
import crypto from 'crypto';
const storage = multer.diskStorage({
destination: 'uploads/',
filename: (req, file, cb) => {
// Never trust the client-provided filename
const random = crypto.randomBytes(8).toString('hex');
const ext = path.extname(file.originalname).toLowerCase();
cb(null, random + ext);
},
});
const allowed = new Set(['image/jpeg', 'image/png', 'image/webp']);
export const upload = multer({
storage,
limits: { fileSize: 5 * 1024 * 1024 }, // 5 MB
fileFilter: (req, file, cb) => {
if (allowed.has(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('Unsupported file type'));
}
},
});Multer configured with a safe filename, MIME type check, and size limit.
Never trust file.originalname. Attackers can include slashes and dots to escape the upload directory: ../../etc/passwd. Generating your own random filename eliminates that entire attack class. The extension comes from the original file, but even that is untrusted at a deeper level, which is why the MIME type check exists too.
The size limit prevents memory exhaustion attacks. Without it, an attacker can upload a 10 GB file and your server runs out of RAM. 5 MB is a reasonable default for images. Adjust it per endpoint: larger for videos, smaller for avatars.
Quiz: Quiz
Loading practice…