Nosql Injection Attack
How Nosql Injection Works
NoSQL injection exploits the way databases like MongoDB, Cassandra, and CouchDB process query parameters. Unlike SQL databases that use structured queries, NoSQL databases often accept JSON-like query objects where attackers can manipulate the structure to bypass authentication or access unauthorized data.
The attack works by injecting operators like $ne (not equal), $gt (greater than), or $exists into query parameters. Consider this MongoDB query:
db.users.find({
username: req.body.username,
password: req.body.password
})If an attacker sends username=admin and password[$ne]= (empty string), the resulting query becomes:
{
username: "admin",
password: { $ne: "" }
}This translates to "find users where username equals admin AND password does NOT equal empty string." Since most passwords aren't empty, this returns the admin user without knowing the actual password.
Another common technique uses $where clauses to execute arbitrary JavaScript in MongoDB:
db.users.find({
$where: "this.username == 'admin' && this.password.length > 0"
})This bypasses the application's authentication logic entirely. Attackers can also use projection operators to extract specific fields or leverage logical operators like $or to create conditions that always evaluate true.
Nosql Injection Against APIs
API endpoints are particularly vulnerable to NoSQL injection because they often directly pass client-provided JSON to database queries. REST APIs that accept JSON payloads for filtering, searching, or authentication are prime targets.
Consider an API endpoint for user authentication:
POST /api/auth
Content-Type: application/json
{
"email": "[email protected]",
"password": "secret123"
}If the backend code directly uses these values in a MongoDB query without validation, an attacker could send:
POST /api/auth
Content-Type: application/json
{
"email": {"$ne": null},
"password": {"$ne": ""}
}This bypasses authentication by finding any user with a non-null email and non-empty password.
Search APIs are equally vulnerable. A product search endpoint might accept filter parameters:
GET /api/products?category=electronics&price[$lt]=100An attacker could manipulate this to extract all products regardless of price by using operators like $where or $regex to create always-true conditions.
GraphQL APIs face similar risks since GraphQL queries are ultimately resolved to database operations. A malicious query could include NoSQL operators in variables that bypass authorization checks.
The risk increases when APIs combine NoSQL injection with other vulnerabilities. For example, an IDOR (Insecure Direct Object Reference) combined with NoSQL injection could let attackers access any user's data by manipulating both the resource identifier and query parameters.
Detection & Prevention
Detecting NoSQL injection requires monitoring for suspicious query patterns and testing with known payloads. Look for requests containing MongoDB operators like $where, $regex, $ne, $gt, $lt, $exists, $or, and $and in unexpected contexts.
Security scanners can automate this testing. For example, middleBrick's NoSQL injection checks attempt to authenticate with manipulated payloads containing $ne operators and $where clauses to detect vulnerable endpoints. The scanner tests authentication flows, search endpoints, and any API accepting JSON parameters.
Prevention strategies include:
- Input validation: Validate and sanitize all JSON input, rejecting suspicious operators
- Parameterized queries: Use query builders or ORMs that properly escape user input
- Least privilege: Database users should have minimal permissions required
- Allowlist filtering: Only allow expected fields and operators in query parameters
- Schema validation: Validate incoming JSON against expected schemas before processing
Code example of safe implementation:
const { email, password } = req.body;
// Validate input types
if (typeof email !== 'string' || typeof password !== 'string') {
return res.status(400).json({ error: 'Invalid input types' });
}
// Use parameterized queries
const user = await db.users.findOne({
email: email,
password: password
});For search functionality, implement strict filtering:
const allowedFilters = ['category', 'price', 'status'];
const query = {};
for (const [key, value] of Object.entries(req.query)) {
if (allowedFilters.includes(key) && typeof value === 'string') {
query[key] = value;
}
}Regular security testing with tools like middleBrick helps identify vulnerabilities before attackers do. The scanner's continuous monitoring can alert you when new endpoints are added that might be vulnerable to NoSQL injection.