This article explains NoSQL injection through a practical lab exercise where attackers bypass login by sending a MongoDB query operator object instead of a password string. The vulnerability arises when applications pass untrusted JSON directly into database queries without validating data types. Understanding this attack is critical because it affects modern JSON APIs and Node.js/Express applications that forward request bodies unvalidated into query builders.
- NoSQL injection changes query structure, not stringsUnlike SQL injection which breaks out of quoted strings, NoSQL injection exploits the fact that document databases accept structured queries. When an app builds a MongoDB filter from untrusted JSON, an attacker can slip in a query operator object instead of a simple value, causing the database to interpret it as a command rather than data. For example, sending `{"password": {"$ne": "impossible"}}` makes the password check always true by asking for any value not equal to an impossible string.
- The MongoLogin vulnerable patternMongoLogin accepts a JSON body with username and password fields and passes them directly to MongoDB as a query filter without type validation. Because the backend never checks whether the password is actually a string, sending an object causes MongoDB to interpret the object keys as operators. The login succeeds when the query structure is manipulated to match the admin record regardless of the actual password.
- Attack exploits missing type validationThe core vulnerability is that the backend trusts the JSON body to contain two strings and never validates the type before the data reaches the database. An attacker sends a not-equal operator against an impossible value in the password field, creating a condition that is always true. Since username remains 'admin', the query effectively reads 'username is admin AND password is anything', matching the admin record.
- Real-world prevalence in modern APIsNoSQL injection commonly appears in Node.js and Express applications that forward `req.body` directly into MongoDB find() without type checks. OWASP tracks it under the Injection category at A03 in the 2021 Top 10, and it is a recurring finding in JSON API bug bounties. The vulnerability is widespread because JSON APIs naturally accept structured input, making it easy for developers to accidentally pass unvalidated objects into query builders.
- Type validation as primary defenseThe article emphasizes that the password field must be validated and cast to a string before reaching the database, rejecting any input that is not a string. Using a schema layer or validated model prevents request bodies from introducing arbitrary operators. Building the filter from named, type-checked fields rather than passing raw request bodies eliminates the structural manipulation that makes NoSQL injection possible.
- Database is not the root causeThe vulnerability exists not because MongoDB is inherently insecure, but because the application passes unvalidated user input directly into query construction. MongoDB behaves correctly by interpreting operators when given structured objects; the bug is entirely in how the application handles untrusted input before submitting it to the database.
- Testing approach for authorized assessmentsOn any JSON API you are authorized to test, the article recommends sending an object where the application expects a string and observing whether behavior changes, such as authentication being bypassed. If the response or auth state differs when sending `{"$operator": "value"}` instead of a string, the input is reaching a query engine that trusts its structure and is likely vulnerable.
Bottom line: NoSQL injection succeeds by submitting query operator objects where applications expect simple string values, exploiting missing type validation before data reaches the database. The defense is straightforward: validate and cast all input types before any value reaches a query builder, treating every client value as data and never allowing it to influence query structure.
📋 In this walkthrough
What this lab teaches
NoSQL injection abuses the fact that document databases like MongoDB take structured queries, not flat strings. When an app builds a query directly from untrusted JSON, an attacker can slip in query operators instead of values.
The lesson: the danger is not special characters, it is letting the user control the structure of the query. SQL injection breaks out of a string; NoSQL injection changes a value into an object the database treats as a command.
How MongoLogin checks your password
You submit {"username":"admin","password":"..."} and the backend hands that object straight to MongoDB as the query filter. Because your input becomes part of the filter, whatever you put in the password field is interpreted by the database, not compared as a plain string.
The attack approach
- Notice the login accepts a JSON body, not a normal form — the password value is passed into the query untouched.
- Instead of a password string, send an object that uses a MongoDB comparison operator.
- Pick an operator that matches any stored value, so the password check is always true.
- Submit with username admin and watch the query match the admin record regardless of the real password.
Full walkthrough (spoiler)
Tried a few shapes and still locked out? Open the steps. Working it out yourself first is worth more XP.
Show the step-by-step solution
- Switch the password from a string to an object in the JSON body.
- Use a not-equal style operator against an impossible value so the comparison is always true for every document.
- Keep the username as admin so the filter still targets the admin account.
- Send it. The query now reads 'username is admin AND password is anything', so the admin record matches and you are logged in. The lab detects the admin session and marks you solved.
Why it works
The backend trusts the JSON body to be two strings and never validates the type. MongoDB sees an object where it expected a value, interprets the key as an operator, and happily evaluates it. No quote-breaking, no payload encoding — the bug is purely structural: user input decided how the query behaves.
Where this happens in the real world
NoSQL injection shows up wherever a request body is passed into a query builder without type checks — common in Node.js and Express apps that forward req.body straight into a MongoDB find(). It is a recurring bug-bounty finding in JSON APIs, and OWASP tracks it under Injection, which sits at A03 in the OWASP Top 10 (2021) alongside SQL injection.
How to defend against it
- Validate and cast types. The password must be a string — reject anything that is not, before it reaches the query.
- Use a schema layer (such as a validated model) so request bodies cannot introduce arbitrary operators.
- Never pass raw request bodies into a query. Build the filter from named, type-checked fields.
- Compare password hashes explicitly rather than letting the database match the value.
Try it, then go further
Reading about it is the easy part. Open the lab, try your own approach before peeking at the spoiler, and see how many attempts it takes.
