NoSQL Injection

Just because you don't use SQL, doesn't mean you can't be injected.

The idea

Many developers falsely believe that using a NoSQL database (like MongoDB or CouchDB) makes them immune to injection attacks. While traditional SQL injection (`' OR 1=1`) won't work, NoSQL databases have their own query languages, usually based on JSON or JavaScript. If user input alters the logic of these JSON structures, it results in NoSQL Injection.

Step 1: Normal Login. The server expects a string password.

How it works (Operator Injection)

In MongoDB, queries are built using JSON objects. Special operators start with a `$` (e.g., `$gt` for greater than, `$ne` for not equal). If an application blindly accepts JSON from a client and passes it to MongoDB, an attacker can supply an object with a `$ne` operator instead of a string, bypassing authentication.

# VULNERABLE: Node.js / Express with MongoDB
app.post('/login', (req, res) => {
    // req.body.password might be a String ("pass123") 
    // OR it could be an Object ({"$ne": null})
    db.collection('users').findOne({
        username: req.body.username,
        password: req.body.password // DANGER! Unvalidated type.
    });
});

# SECURE: Enforce Data Types
app.post('/login', (req, res) => {
    // Explicitly cast to a string to strip out MongoDB operators.
    db.collection('users').findOne({
        username: String(req.body.username),
        password: String(req.body.password)
    });
});

Watch out for

Worked example

A login form sends a POST request with `{"username": "admin", "password": {"$gt": ""}}`. The Node.js server passes `req.body.password` directly into the Mongoose query. The database receives: `Find a user where username is 'admin' AND password is greater than an empty string.` Since every password is greater than an empty string, the query succeeds and the attacker logs in as Admin without knowing the password.

Check yourself

How does type casting (e.g., `String(input)`) prevent NoSQL operator injection in MongoDB?

No. Type casting does not perform encryption.
Correct! By forcing the input to be a primitive string, it destroys the JSON object structure required for MongoDB operators to function.