Thursday, December 4, 2025

thumbnail

Secure File Uploads in MERN

 Secure File Uploads in MERN (MongoDB, Express, React, Node)


File uploads are a high-risk feature. Attackers can upload:


Malware


Scripts (XSS, RCE payloads)


Oversized files (DoS)


Poisoned images or PDFs


Wrong MIME types


Files with misleading extensions


To secure a MERN upload pipeline, you must validate, sanitize, scan, and isolate uploaded files.


๐Ÿงฑ 1. Frontend (React) File Validation


Frontend validation is not security, but improves UX. Backend still does all enforcement.


React example:

const allowedTypes = ["image/jpeg", "image/png"];

const maxSize = 5 * 1024 * 1024; // 5MB


function handleFile(e) {

  const file = e.target.files[0];


  if (!allowedTypes.includes(file.type)) {

    alert("Only JPEG/PNG allowed.");

    return;

  }


  if (file.size > maxSize) {

    alert("File is too large.");

    return;

  }

}



✔ UX validation

✘ NOT a security control (still bypassable)


๐Ÿงฉ 2. Backend Upload Security (Node + Express)


Use Multer or Busboy for parsing uploads — but wrap them in secure configs.


Install Multer

npm install multer


2.1 Multer Secure Configuration

const multer = require("multer");

const path = require("path");


const storage = multer.memoryStorage(); // safer than diskStorage for validation


const upload = multer({

  storage,

  limits: {

    fileSize: 5 * 1024 * 1024, // 5MB

  },

  fileFilter: (req, file, cb) => {

    const ext = path.extname(file.originalname).toLowerCase();

    const allowed = [".jpg", ".jpeg", ".png", ".pdf"];


    if (!allowed.includes(ext)) {

      return cb(new Error("Invalid file type"), false);

    }


    if (!file.mimetype.startsWith("image/") && ext !== ".pdf") {

      return cb(new Error("MIME type mismatch"), false);

    }


    cb(null, true);

  },

});


Why memoryStorage?


Prevents writing malicious files to disk before checks


Ideal when you plan to upload to cloud storage (S3, Cloudinary, Firebase)


๐Ÿงผ 2.2 Sanitizing File Names


Attackers can poison filenames:


const sanitizeFilename = require("sanitize-filename");


const safeName = sanitizeFilename(file.originalname).replace(/\s+/g, "_");



Never trust the original filename.


๐Ÿ›‘ 2.3 Block Dangerous File Types


Even if disguised:


.js, .exe, .php, .html, .svg


Double extensions (image.png.exe, file.jpg.php)


Files with null bytes (file.jpg\0.exe)


๐Ÿ›ก️ 2.4 Virus/Malicious Content Scanning (Optional but Strongly Recommended)


Use ClamAV, Cloud antivirus APIs, or VirusTotal:


npm install clamscan



Example:


const NodeClam = require('clamscan');


const clamscan = await new NodeClam().init();


const { is_infected } = await clamscan.scan_buf(file.buffer);

if (is_infected) throw new Error("Malicious file detected");


☁️ 3. Store Files Safely (Cloud Recommended)

Never store untrusted uploads inside your app directory


If an attacker uploads malware.php, they might execute it if served publicly.


Safer options:


AWS S3 with private buckets


Cloudinary


Firebase Storage


Azure Blob Storage


AWS S3 Upload Example

const AWS = require("aws-sdk");

const s3 = new AWS.S3();


const params = {

  Bucket: process.env.S3_BUCKET,

  Key: safeName,

  Body: file.buffer,

  ContentType: file.mimetype,

  ACL: "private",

};


await s3.upload(params).promise();



✔ No executable permissions

✔ Versioning

✔ Access control

✔ Scalable


๐Ÿงฑ 4. MongoDB Security


Do NOT store raw file binaries in MongoDB unless necessary. Prefer cloud storage, store only metadata:


{

  filename: safeName,

  url: s3Url,

  size: file.size,

  uploadedBy: userId,

  createdAt: Date.now()

}



If using GridFS:


Set strict file size limits


Validate metadata before saving


๐Ÿ” 5. Endpoint Hardening

✔ Rate limit uploads

const rateLimit = require("express-rate-limit");


app.use("/upload", rateLimit({

  windowMs: 10 * 60 * 1000,

  max: 20, // 20 uploads per 10 min

}));


✔ Validate user authentication before upload


JWT


OAuth


Session auth


✔ Enforce API-level validation


Required user roles


File purpose constraints


๐Ÿงณ 6. Serve Files Securely

1. Signed URLs (Best Practice)


Let clients download files via expiring URLs.


2. Never serve files directly from a writable directory


This prevents arbitrary code execution.


3. Remove EXIF metadata


Prevents location leaks for uploaded photos.


๐Ÿ”’ 7. Production Best Practices

✔ Limit max upload size at all layers:


React


Express (body size limit)


NGINX/Apache reverse proxy


Cloud storage


✔ Disable file execution in upload directories


If using a local upload directory:


On Linux: set noexec mount option


Block running .js, .php, .py, etc.


✔ Validate images with a library (sharp / imagemagick)


To prevent “polyglot” file attacks.


const sharp = require("sharp");


await sharp(file.buffer).metadata(); // throws on invalid image


✔ Use HTTPS for all uploads


Avoid on-path tampering.


๐Ÿงช 8. End-to-End Secure Upload Flow (Recommended)

React:

    ↓ Validate type and size

Express:

    ↓ Multer with memoryStorage

    ↓ Validate extension + mime

    ↓ Sanitize filename

    ↓ virus scan (optional)

    ↓ validate authentic image (sharp)

    ↓ upload to S3 / Cloud storage

MongoDB:

    ↓ store metadata only

Client:

    ↓ access using signed URL



This is the industry-standard MERN upload architecture.


๐ŸŽ‰ Summary: Essential Security Controls

Security Layer Purpose

File type/size validation Prevent unwanted files

Filename sanitization Prevent path/command injection

MIME sniffing Block file type spoofing

Virus scanning Malware prevention

Cloud storage Isolation + access control

Rate limiting Prevent DoS

Auth checks Prevent unauthorized uploads

Metadata-only in Mongo Prevent DB bloat & exploitation


This combination gives you a production-grade secure upload pipeline.

Learn MERN Stack Training in Hyderabad

Read More

Rate Limiting & Throttling with Express

Using Helmet for Express Security

Storing Passwords Securely with bcrypt

Role-Based Access Control in MERN Stack

Visit Our Quality Thought Training Institute in Hyderabad

Get Directions 

Subscribe by Email

Follow Updates Articles from This Blog via Email

No Comments

About

Search This Blog

Powered by Blogger.

Blog Archive