NoSQL Injection
When JSON values flow into a document-database query as operators — bypassing login, defeating operator blacklists, and leaking data one character at a time.
- Track
- Web security
- Estimated time
- 25 min
- Level
- Intermediate
Before this lesson
NoSQL databases (MongoDB and friends) query with structured objects, not a string language. That removes the classic SQL quote-breaking — but opens a new door: if user-supplied JSON flows into the query filter without a type check, the attacker can send an operator object where the app expected a plain value, and change what the query means.
What is the vulnerability?
A login builds its filter straight from the request body:
const user = db.users.findOne({ username: req.body.username, password: req.body.password });If password arrives as the string "guess", it is compared for equality. But if the client sends {"password": {"$ne": null}}, the value is an operator that matches any password — login bypassed, no secret needed.
Why does it happen?
The app assumed every JSON value is a string. JSON can also carry objects, and the query layer treats a $-prefixed key as an operator. Trying to fix it by banning $ne is a blacklist: $gt, $in, $regex all remain, and $regex even turns a yes/no login into an oracle that leaks the stored value one character at a time.
How do you stop it?
Type-check every value before it reaches the query: a credential must be a string, never an object. Compare passwords against a stored hash, not a live value. Do not chase operators one by one — reject the wrong shape outright.
The three labs below are exactly this ladder: an operator login bypass, a $ne blacklist beaten by $gt, and blind $regex extraction of the admin password.
Labs
Operator login bypass
SolvedEasyBrowser lab
Sign in as admin without its password, using a NoSQL operator.
Enter the labLockedAn operator blacklist
SolvedMediumBrowser lab
Sign in as admin using an operator other than ne.
Enter the labLockedBlind regex extraction
SolvedHardBrowser lab
Extract the full admin password via regex, then submit it.
Enter the labLocked
