Skip to main content
Offensive360
Home / Knowledge Base / NoSQL Injection (MongoDB)
High CWE-943 A03:2021 Injection

NoSQL Injection (MongoDB)

NoSQL injection attacks manipulate MongoDB and other NoSQL queries using operator injection, allowing authentication bypass and unauthorized data access. Learn detection and prevention.

Affects: JavaScriptPythonC#JavaPHP

What is NoSQL Injection?

NoSQL injection targets document-oriented and key-value databases like MongoDB, CouchDB, and Redis. Unlike traditional SQL injection, attackers don’t inject SQL syntax — instead, they inject query operators or manipulate JSON structures to alter the intended query logic.

MongoDB’s query language accepts rich JSON objects with special operators (e.g., $gt, $ne, $where, $regex). If user-supplied JSON or form data is deserialized and passed directly into a query, an attacker can inject these operators to bypass filters, extract arbitrary documents, or enumerate the entire database.

How exploitation works

A Node.js login endpoint queries MongoDB with user-supplied credentials:

// Application query: { username: "alice", password: "secret" }
db.users.findOne({ username: req.body.username, password: req.body.password });

An attacker sends this JSON body:

{ "username": "admin", "password": { "$ne": "" } }

MongoDB evaluates { "password": { "$ne": "" } } — password not equal to empty string — which is true for every user. The attacker authenticates as admin without knowing the password.

Vulnerable code examples

Node.js / Express + MongoDB

// VULNERABLE: Body parsed as JSON and passed directly to MongoDB query
app.post('/login', async (req, res) => {
  const user = await db.collection('users').findOne({
    username: req.body.username,    // Could be an object like { $ne: null }
    password: req.body.password
  });
  if (user) return res.json({ token: generateToken(user) });
  return res.status(401).json({ error: 'Invalid credentials' });
});

PHP / MongoDB

// VULNERABLE: $_POST data directly used in MongoDB query
$user = $collection->findOne([
    'username' => $_POST['username'],
    'password' => $_POST['password']  // Attacker can pass ["$ne" => ""]
]);

Secure code examples

Node.js — type enforcement

// SECURE: Explicitly cast to string and validate format before querying
app.post('/login', async (req, res) => {
  const username = String(req.body.username ?? '');
  const password = String(req.body.password ?? '');

  // Reject if not valid strings (operators would be objects)
  if (typeof req.body.username !== 'string' || typeof req.body.password !== 'string') {
    return res.status(400).json({ error: 'Invalid input' });
  }

  const user = await db.collection('users').findOne({ username, password: hashPassword(password) });
  if (user) return res.json({ token: generateToken(user) });
  return res.status(401).json({ error: 'Invalid credentials' });
});

Python / PyMongo — explicit string casting

# SECURE: Cast inputs to strings and hash passwords before querying
from pymongo import MongoClient
import hashlib

def login(username_input, password_input):
    # Force string type — dict/operator injection impossible
    username = str(username_input)
    password_hash = hashlib.sha256(str(password_input).encode()).hexdigest()

    user = db.users.find_one({"username": username, "password_hash": password_hash})
    return user

What Offensive360 detects

  • Unsanitized query objects — MongoDB find(), findOne(), update() calls receiving user-controlled objects without type validation
  • $where operator with user input — JavaScript expressions in $where clauses that include tainted data (enables JavaScript injection)
  • Mongoose query selector injection — Mongoose models queried with unsanitized req.body or req.query objects
  • Array/object operator injection — Endpoints parsing JSON bodies that are passed directly into query selectors

Remediation guidance

  1. Enforce type checking — Validate that fields expected to be strings are indeed strings before using them in queries. Reject objects or arrays.

  2. Use schema validation — Libraries like Joi, Zod, or Mongoose schema validators enforce input shape before data reaches the database.

  3. Hash passwords before comparison — Never compare passwords in plaintext within MongoDB queries; use bcrypt or Argon2 and compare hashes.

  4. Avoid the $where operator$where executes JavaScript on the server; never use it with user input, and disable it at the MongoDB level if not needed.

  5. Use an ODM/ORM appropriately — Mongoose’s typed models reduce injection risk, but raw .find(req.body) patterns remain dangerous.

References

By Offensive360 Security Research Reviewed: March 2026

Detect NoSQL Injection (MongoDB) automatically

Run Offensive360 SAST on your codebase to find this and 100+ other vulnerabilities.