NoSQL injection: rewriting MongoDB queries from a request
NoSQL databases do not parse SQL, but they still interpret structure. A request that sends an object where you expected a string, or text that ends up inside a $where expression, changes what the query means.
Example
// $where runs JavaScript inside MongoDB
allocations.find({
$where: `this.userId == ${userId} && this.stocks > '${req.query.threshold}'`
});
// {"password": {"$ne": null}} matches any user
users.findOne({ user: req.body.user, password: req.body.password });const threshold = Number.parseInt(req.query.threshold, 10);
if (!(threshold >= 0 && threshold <= 99)) return res.sendStatus(400);
allocations.find({ userId, stocks: { $gt: threshold } });
users.findOne({ user: String(req.body.user) });
// then compare the password hash with bcrypt.compareHow it happens
Two shapes. $where takes JavaScript that MongoDB runs for every document, so a value such as 1'; return true; ' returns everything and a busy loop can stall the server. Operator injection is quieter: body parsers turn password[$ne]= into {"$ne": ""}, and a login query that drops the request value in unchanged then matches any account.
How to fix it
Keep request data as plain values.
- Do not use $where; express conditions with query operators
- Cast values to the type you expect (String, Number) before querying
- Enable Mongoose sanitizeFilter, or strip keys starting with $ from input
- Look users up by name, then verify the password hash separately
How RepoVerse finds it
- HighRequest input runs inside a MongoDB `$where` expression
`$where` is JavaScript evaluated by the database. A crafted value can return every document (`1'; return true; '`) or hang the server (`';while(true){}'`).
data flow · CWE-943
- ModerateRequest value used directly as a MongoDB filter value
If the body parser accepts objects, `{"$ne": null}` or `{"$gt": ""}` in that field matches any document — the classic login bypass.
data flow · CWE-943
Questions
- Is MongoDB immune to injection because it has no SQL?
- No. $where executes JavaScript, and query operators passed in from a request change which documents match. Both are classified as CWE-943.
- How does RepoVerse detect NoSQL injection?
- It traces request input into $where strings — including across files into a data-access layer — and flags request values used directly as filter values, which can carry operator objects.
Related
- SQL injection: what it is and how to fix itWhat SQL injection (CWE-89) is, a vulnerable query next to the fixed one, and how to find string-built SQL in your code with data-flow analysis.
- Code injection: request input passed to evalWhy eval, new Function and string timers on request data mean remote code execution (CWE-95), a real example from OWASP NodeGoat, and the fix.
- Password storage: hash with bcrypt, scrypt or Argon2Why passwords must never be stored in plaintext or with MD5/SHA-1 (CWE-256, CWE-916), and how to hash and verify them correctly with bcrypt, scrypt or Argon2.
Updated 2026-10-11