Skip to main content
ESLint Interlace
Plugin: mongodb-securityRules

no-operator-injection

Detects MongoDB operator injection attacks where user input is passed directly as query values, allowing attackers to...

Keywords: NoSQL injection, CWE-943, MongoDB, $ne, $gt, $or, operator injection, security

Detects MongoDB operator injection attacks where user input is passed directly as query values, allowing attackers to inject operators like $ne, $gt, $or to bypass authentication or exfiltrate data.

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

Quick Summary

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

Value & investment case

Why this rule pays for itself. Framework: cicd-impact/philosophy.md.

DimensionValue
CWECWE-943 — Improper Neutralization of Special Elements in Data Query Logic (NoSQL injection, CVSS 9.1)
Feedback-loop tierEditor / pre-commit (sub-second) — cheapest layer per the feedback-loop hierarchy
Defensive-layer leverage~10× cheaper than unit-test · ~1,000× cheaper than production rollback · 10,000+× cheaper than customer disclosure (cost-ratio anchors)
Niche relevanceCritical: fintech, healthtech, B2B SaaS (any MongoDB-backed multi-tenant app) · High: marketplaces, infra/devtools · Medium: B2C
Investor-frame impactNoSQL operator injection ($ne, $gt, $or injection) → authentication bypass + data exfiltration. The MongoDB-specific equivalent of SQL injection; same class of disclosure event. Catch at lint-time prevents the entire attack family.

Read also: philosophy.md §investor-frame · niche-presets.json · analyzer-evaluation-framework.md

Rule Details

This rule specifically targets operator injection - a subset of NoSQL injection where attackers submit objects with MongoDB operators instead of expected primitive values.

Attack Scenario

// Expected: { username: "john", password: "secret123" }
// Attacker sends: { username: "admin", password: { "$ne": "" } }

// This query:
db.users.findOne({ username: req.body.username, password: req.body.password });

// Becomes:
db.users.findOne({ username: 'admin', password: { $ne: '' } });
// Matches admin user with ANY non-empty password - authentication bypass!

❌ Incorrect

const filter = { $ne: req.body.value };

✅ Correct

// Force value comparison with $eq
User.findOne({ email: { $eq: req.body.email } });

// Cast to primitive type
User.findOne({ email: String(req.body.email) });

// Validate input is not an object
if (typeof req.body.email !== 'string') throw new Error('Invalid input');
User.findOne({ email: req.body.email });

Known False Negatives

Object Spread

// ❌ NOT DETECTED - spreads entire body into query
User.findOne({ ...req.body });

Dynamic Property Access

// ❌ NOT DETECTED - dynamic key assignment
const query = {};
query[field] = value;

Aggregation Pipelines

// ❌ NOT DETECTED - complex pipeline structure
User.aggregate([{ $match: req.body.filter }]);

When Not To Use It

  • When using Mongoose schema with strict validation that rejects object values
  • When all input is validated through a strict JSON schema (e.g., Zod, Joi)
  • In test files with intentionally vulnerable patterns

References

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.