Interlace ESLint
ESLint Interlace
MongoDBRules

no-unsafe-query

Prevents NoSQL injection by detecting direct use of user input in MongoDB query objects.

Keywords: NoSQL injection, CWE-943, MongoDB, Mongoose, operator injection, query manipulation, security

Prevents NoSQL injection by detecting direct use of user input in MongoDB query objects.

⚠️ This rule errors by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-943 (NoSQL Injection)
OWASPA03:2021 - Injection
SeverityCritical (CVSS: 9.8)
CategorySecurity
ESLint MCP✅ Optimized for AI assistant integration

Rule Details

NoSQL injection allows attackers to bypass authentication or extract data by manipulating query operators. Unlike SQL injection which uses strings, NoSQL injection exploits the ability to pass objects with operators like $ne, $gt, $or.

Attack Example

// Attacker sends: { "password": { "$ne": null } }
// This becomes: { email: "victim@test.com", password: { $ne: null } }
// Which matches ANY user with that email, bypassing password check!

❌ Incorrect

// Direct req.body in query - allows operator injection
User.find({ email: req.body.email });

// Direct req.query in query
db.collection('users').findOne({ username: req.query.user });

// Direct req.params in query
User.updateOne({ _id: req.params.id }, { $set: { active: true } });

✅ Correct

// Wrap with $eq operator - forces value comparison
User.find({ email: { $eq: req.body.email } });

// Cast to string to prevent object injection
db.collection('users').findOne({ username: { $eq: String(req.query.user) } });

// Use ObjectId constructor for ID fields
User.updateOne(
  { _id: new ObjectId(req.params.id) },
  { $set: { active: true } },
);

// Use schema validation + sanitization
const email = sanitize(req.body.email);
User.find({ email: { $eq: email } });

Error Message Format

🔒 CWE-943 OWASP:A03:2021-Injection CVSS:9.8 | NoSQL injection via user input | CRITICAL
   Fix: Wrap user input with explicit $eq operator: { field: { $eq: sanitize(value) } }

Options

{
  "rules": {
    "mongodb-security/no-unsafe-query": [
      "error",
      {
        "allowInTests": true,
        "additionalMethods": ["customFind"]
      }
    ]
  }
}
OptionTypeDefaultDescription
allowInTestsbooleantrueSkip detection in .test.ts/.spec.ts
additionalMethodsstring[][]Additional method names to check

Known False Positives

These patterns are safe but may be flagged:

Variables Not From User Input

// FP: Variable from database/config, not user input
const adminEmail = config.adminEmail; // Hardcoded or from config
User.find({ email: adminEmail }); // ← May flag but is safe

Workaround: Use $eq pattern consistently, or add to allowPatterns.

Sanitized Input Without $eq

// FP: Input is sanitized but not wrapped in $eq
const safeEmail = sanitize(req.body.email);
User.find({ email: safeEmail }); // ← May flag

Workaround: Always use { $eq: value } pattern.

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Dynamic Query Building

Why: Query built programmatically cannot be traced.

// ❌ NOT DETECTED
const query = {};
query[field] = req.body.value; // Dynamic property
User.find(query);

Spread Operator Injection

Why: Spread operators merge objects at runtime.

// ❌ NOT DETECTED
User.find({ ...baseQuery, ...req.body }); // Entire body spread into query

Indirect Variable Assignment

Why: Multi-step variable flow isn't tracked.

// ❌ NOT DETECTED
let query = { email: 'safe@test.com' };
query = { email: req.body.email }; // Reassignment not tracked
User.find(query);

Function Parameter Passthrough

Why: Values passed through functions aren't traced.

// ❌ NOT DETECTED
function findByEmail(email) {
  return User.find({ email }); // Can't determine source of 'email'
}
findByEmail(req.body.email);

Aggregation Pipeline

Why: Complex pipeline stages aren't analyzed.

// ❌ NOT DETECTED
User.aggregate([
  { $match: { email: req.body.email } }, // Variable in pipeline
]);

Recommendation: Always validate/sanitize user input AND use $eq wrapper. Defense in depth!

When Not To Use It

  • When using ODM schema validation that prevents object injection
  • In migration files with static queries
  • When all input passes through strict validation layer
  • In test files (use allowInTests: true)

References

On this page