no-operator-injection
Detects MongoDB operator injection attacks where user input is passed directly as query values, allowing attackers to...
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
| Aspect | Details |
|---|---|
| CWE Reference | CWE-943 (NoSQL Injection) |
| OWASP | A03:2021 - Injection |
| Severity | Critical (CVSS: 9.1) |
| Category | Security |
| ESLint MCP | ✅ Optimized for AI assistant integration |
Value & investment case
Why this rule pays for itself. Framework:
cicd-impact/philosophy.md.
| Dimension | Value |
|---|---|
| CWE | CWE-943 — Improper Neutralization of Special Elements in Data Query Logic (NoSQL injection, CVSS 9.1) |
| Feedback-loop tier | Editor / 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 relevance | Critical: fintech, healthtech, B2B SaaS (any MongoDB-backed multi-tenant app) · High: marketplaces, infra/devtools · Medium: B2C |
| Investor-frame impact | NoSQL 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
Related Rules
- no-unsafe-query - General unsafe query detection
- no-unsafe-where - $where operator detection
References
⚙️ Options
| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Skip this rule in *.test.* / *.spec.* files |
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.