The Ravens API takes a JSON login and builds a document-database query filter straight from it. Make the password an operator object like ne and it matches any password, logging you in as admin.
A login screen that posts JSON with username and password. The server passes both values as-is into the query filter, so if password is an operator object rather than a string it changes the query meaning.
Sign in as admin without its password, using a NoSQL operator.
You signed in as admin with a NoSQL operator.
Why the solution worked
The JSON values entered the query filter with no type check, becoming operators that control matching. The fix is forcing values to be strings and never passing user objects into the filter.
The root cause
Passing user JSON values into the query filter with no type check, so they become operators. The root is trusting the structure of user input.
How the code is fixed
Force login values to be strings and never pass user objects into the query filter.
Vulnerable code
app.post('/login', (req, res) => {
// req.body.password may be { $ne: null } and still flow into the query.
const user = db.users.findOne({ username: req.body.username, password: req.body.password });
});
Safe code
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (typeof username !== 'string' || typeof password !== 'string') return res.status(400).end();
const user = db.users.findOne({ username, password: hash(password) });
});
Impact in the real world
NoSQL injection bypasses login and reads or alters data in document databases, common in APIs that accept JSON.
How defenders detect it
Defenders type-check every field, reject objects where a string is expected, and alert on values with $-prefixed keys.