Mongoose: Connection-level sanitizeFilter not appliedGHSA-gg4r-jv3p-qx3c
HIGHFix: Automattic/mongoose@4bb6594GHSA-gg4r-jv3p-qx3c is a high-severity (CVSS 7.5) CWE-943 vulnerability in mongoose. A fix is available for mongoose — see the affected versions and patch details below.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
Where this sits among everything scored
Real-World Exposure
How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.
mongoosenpmDescription
Summary
sanitizeFilter exists to stop query selector injection: it wraps operator objects such as { $ne: null } in filter values in $eq, so they are matched literally. Set on a connection with mongoose.connect() or createConnection(uri, { sanitizeFilter: true }), the connection reports it as enabled but queries never apply it. An application that relies on the connection-level option and passes an attacker-controlled object into a filter therefore remains open to selector injection, and a password value of { $ne: null } returns the account record without the password.
Details
NativeConnection#createClient() at lib/drivers/node-mongodb-native/connection.js:270-272 moves options.sanitizeFilter into Connection.config and deletes the original option. Query#_castConditions() at lib/query.js:2413-2423 checks Connection.options, the global options, and the per-query options, but never Connection.config. The defense therefore does not run even though Connection#get('sanitizeFilter') returns true. This storage was introduced in Mongoose 6.0.0 and the same mismatch is present in 9.11.2.
Proof of concept
import mongoose from 'mongoose'
const conn = await mongoose.createConnection('<MONGODB_URI>', { sanitizeFilter: true }).asPromise()
const User = conn.model('User', new mongoose.Schema({
username: String,
password: String,
marker: String
}))
await User.create({
username: 'victim',
password: 'correct-password',
marker: 'PROTECTED_RECORD'
})
const filter = { username: 'victim', password: { $ne: null } }
console.log(conn.get('sanitizeFilter'))
console.log((await User.findOne(filter).lean()).marker)
A control query with a literal wrong password returned no document in the same run, confirming the filter is otherwise enforced.
Impact
Connection-level sanitizeFilter option is not respected. Any user that relies on connection-level config and sanitizeFilter to defend against query selector injection is affected. Users that set sanitizeFilter globally using mongoose.set('sanitizeFilter') or on specific queries using Model.find().sanitizeFilter() are not affected.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 📦npm | mongoose | ≥ 6.0.0&&< 6.13.12 | 6.13.12npm install mongoose@6.13.12 |
| 📦npm | mongoose | ≥ 7.0.0&&< 7.8.13 | 7.8.13npm install mongoose@7.8.13 |
| 📦npm | mongoose | ≥ 8.0.0&&< 8.24.7 | 8.24.7npm install mongoose@8.24.7 |
| 📦npm | mongoose | ≥ 9.0.0&&< 9.11.4 | 9.11.4npm install mongoose@9.11.4 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for mongoose, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update mongoose to 6.13.12 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-gg4r-jv3p-qx3c is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
Frequently Asked Questions
Is GHSA-gg4r-jv3p-qx3c in your dependencies?
Find it across npm, including transitive dependencies.