Introduction
A gap in Mongoose's query sanitization logic let the $nor operator act as a free pass for injecting arbitrary NoSQL operators into MongoDB queries, bypassing the sanitizeFilter mechanism that developers rely on for protection. For any Node.js application that trusts sanitizeFilter to neutralize user-controlled query input, this vulnerability (CVSS 7.5) opens a direct path to authentication bypass and unauthorized data access.
Mongoose is the dominant MongoDB Object Data Modeling library for Node.js, and Automattic maintains it. It has roughly 2.2 million weekly downloads on npm and over 27,400 GitHub stars, and it powers a significant portion of the Node.js applications that interact with MongoDB. Given that adoption, a sanitization bypass in Mongoose has an outsized blast radius.
Technical Information
Root Cause: Missing $nor in Recursive Sanitization
Mongoose's sanitizeFilter() function, in lib/helpers/query/sanitizeFilter.js, protects against NoSQL injection by iterating over every key in a query filter object. When a value contains dollar-prefixed properties, which the internal hasDollarKeys() helper detects, the function wraps that value in a $eq operator. That neutralizes any injected query operators.
Logical operators like $and and $or accept arrays of sub-condition objects, so the function has to recurse into each element and sanitize it independently. The vulnerable code checked for only two of MongoDB's three logical array operators:
// BEFORE (vulnerable) if (key === '$and' || key === '$or') { sanitizeFilter(value); continue; }
MongoDB's $nor operator is structurally identical to $and and $or, since it also takes an array of condition objects. Because $nor was missing from this check, the function never recursed into its contents. The $nor value also never triggers hasDollarKeys(), because that helper only inspects plain objects for dollar-prefixed keys and the value is an array. Any operators nested inside a $nor clause therefore passed through to MongoDB untouched.
Attack Flow
An attacker exploiting this vulnerability would follow these steps:
-
Find a vulnerable endpoint. The target application must use Mongoose with
sanitizeFilterenabled and pass user-controlled input directly into a query method. A common vulnerable pattern isModel.findOne(req.body), where the entire HTTP request body becomes the MongoDB query filter. -
Build a JSON payload that places malicious query operators inside a
$norarray. Operators like$ne(not equal),$gt(greater than), or$regexcan all be nested within$norclauses. -
Send the payload as the request body to the vulnerable endpoint. Because
sanitizeFilterdoes not recurse into$nor, the malicious operators reach MongoDB's query engine without being wrapped in$eq. -
Use the result. Depending on the application logic, this can mean authentication bypass (e.g., matching any user whose password is not equal to an empty string), unauthorized data enumeration, or data exfiltration.
The CVSS 3.1 vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. The attack is network accessible and low complexity, needs no privileges or user interaction, and has high confidentiality impact.
Applications that explicitly map fields before querying (e.g., Model.findOne({ user: req.body.user, pwd: req.body.pwd })) or that validate input schemas and whitelist fields are not affected by this vulnerability.
Patch Information
The Mongoose maintainers fixed CVE-2026-42334 in commit b804e34, which Valeri Karpov authored on February 4, 2026, with the message "fix: handle other top-level query operators in sanitizeFilter." Patched versions shipped for all supported major release lines: 6.13.9, 7.8.9, 8.22.1, and 9.1.6.
The core fix adds $nor to the set of recursively sanitized logical operators:
// AFTER (patched) if (key === '$and' || key === '$or' || key === '$nor') { sanitizeFilter(value); continue; }
The commit also adds defense-in-depth hardening. Several other potentially dangerous top-level operators that were previously unhandled now throw a MongooseError unless they are wrapped in the trusted() escape hatch:
} else if (key === '$jsonSchema' || key === '$where' || key === '$expr' || key === '$text') { throw new MongooseError(key + ' is not allowed with sanitizeFilter'); }
This is a meaningful addition. Operators like $where, which accepts arbitrary JavaScript, and $expr, which allows aggregation expressions, could be abused for injection if an attacker controlled their values. The commit also updates the trusted() function in lib/helpers/query/trusted.js to accept function types alongside objects, which is necessary because $where can take a function value.
The accompanying test file (test/helpers/query.sanitizeFilter.test.js) gained 81 new lines of coverage. A dedicated test case verifies that nested dollar-key operators inside $nor clauses are now wrapped in $eq. Separate test cases for each newly blocked operator ($jsonSchema, $where, $expr, $text) confirm that they throw when untrusted and pass through when wrapped in trusted().
To apply the fix, upgrade the mongoose npm package to version ^6.13.9, ^7.8.9, ^8.22.1, or ^9.1.6, depending on the major version your application uses.
Affected Systems and Versions
The vulnerability affects all Mongoose versions across four major release lines that include the sanitizeFilter feature:
| Affected Version Range | Fixed Version |
|---|---|
| Versions prior to 6.13.9 | 6.13.9 |
| Versions 7.0.0 through 7.8.8 | 7.8.9 |
| Versions 8.0.0 through 8.22.0 | 8.22.1 |
| Versions 9.0.0 through 9.1.5 | 9.1.6 |
Only applications that explicitly enable sanitizeFilter and pass unsanitized user input directly into query methods are vulnerable. Applications that validate input schemas, whitelist fields, or explicitly map request properties to query parameters are not affected.
Vendor Security History
Mongoose has had query injection vulnerabilities before. CVE-2025-23061 was a critical-severity (CVSS 9.0) search injection vulnerability related to the $where clause. Repeated injection flaws in the query sanitization layer suggest that this part of the codebase is structurally hard to get right. The patch for CVE-2026-42334 reflects awareness of that pattern. Beyond fixing the immediate $nor issue, the commit blocks $where, $expr, $jsonSchema, and $text operators from passing through sanitizeFilter untrusted, which is a welcome defense-in-depth measure.



