You might be using the latest React hooks and a scalable MongoDB cluster, but if your API endpoints are naked, a 15-year-old with a script can wipe your database in seconds.

Here are the 3 most common security holes in MERN apps — and the exact code to fix them.

1. The Silent Killer: NoSQL Injection

The Threat: Everyone talks about SQL Injection, but MERN apps use MongoDB (NoSQL). Developers assume they are safe. They are wrong.

If you pass user input directly to your database, a hacker can send a malicious command instead of a password.

The Vulnerable Code: A hacker sends { "$gt": "" } (greater than nothing) as the password. MongoDB interprets this as "Find any user where the password is greater than an empty string." Result: They log in as Admin without a password.

JavaScript

// DON'T DO THIS
app.post('/login', async (req, res) => {
  // Passing req.body directly allows hackers to inject commands
  const user = await User.findOne({ 
    username: req.body.username, 
    password: req.body.password 
  });
  
  if (user) { /* Logged in as Admin! */ }
});

The Fix (Sanitization): Never trust user input. Use a library like mongo-sanitize to strip out keys that start with $ before they reach your database.

JavaScript

// DO THIS
const sanitize = require('mongo-sanitize');
app.post('/login', async (req, res) => {
  // Clean the input first
  const cleanUsername = sanitize(req.body.username);
  const cleanPassword = sanitize(req.body.password);
  const user = await User.findOne({ 
    username: cleanUsername, 
    password: cleanPassword 
  });
});

2. XSS (Cross-Site Scripting): React's Hidden Trap

The Threat: React is secure by default, but sometimes you need to render HTML from a user (like a blog post or comment).

If you force React to render raw HTML, a hacker can inject a script that steals every visitor's session cookies.

The Vulnerable Code: Using dangerouslySetInnerHTML is… well, dangerous.

JavaScript

// DON'T DO THIS
// If 'userContent' contains <script>alert('Hacked')</script>, it runs.
function BlogPost({ content }) {
  return <div dangerouslySetInnerHTML={{ __html: content }} />;
}

The Fix (Purification): Use DOMPurify to scrub the HTML clean of malicious scripts before rendering it.

JavaScript

// DO THIS
import DOMPurify from 'dompurify';
function BlogPost({ content }) {
  const cleanContent = DOMPurify.sanitize(content);
  return <div dangerouslySetInnerHTML={{ __html: cleanContent }} />;
}

3. The Invisible Shield: HTTP Headers

The Threat: By default, Express.js broadcasts "I am running Express" in the header of every response. This tells hackers exactly what vulnerabilities to look for.

The Fix (Helmet): You don't need to write complex logic here. Just use helmet. It automatically sets secure HTTP headers to hide your tech stack and prevent common attacks.

JavaScript:

// DO THIS
const helmet = require('helmet');
const express = require('express');
const app = express();
// Put this at the top of your middleware stack
app.use(helmet());

Why It Matters (For Business Owners)

Security isn't just code; it's trust.

None

If your SaaS gets breached:

  • You lose customers: 60% of small businesses close within 6 months of a cyber attack.
  • You lose money: Recovering data costs 10x more than securing it.
  • You lose sleep: Do you want to worry about your database every night?

Audit your server.js file today. If you don't see sanitize or helmet, you have work to do.