Skip to main content

NoSQL Injection

· 7 min read
Duong Nguyen Thuan
AI/ML Engineer, MLOps Enthusiast

NoSQL injection is a critical security vulnerability that affects NoSQL databases such as MongoDB, CouchDB, and others. Unlike traditional SQL injection, NoSQL injection exploits the query syntax and structure of NoSQL databases to manipulate application behavior and gain unauthorized access to data.

What is NoSQL Injection?

NoSQL injection occurs when user input is directly incorporated into NoSQL database queries without proper validation or sanitization. Attackers can manipulate these queries to:

  • Bypass authentication mechanisms
  • Extract sensitive data
  • Modify or delete database records
  • Escalate privileges
  • Execute arbitrary code (in some cases)
Security Risk

NoSQL injection can be as devastating as SQL injection, potentially leading to complete database compromise and unauthorized access to sensitive information.

Common NoSQL Database Types and Vulnerabilities

MongoDB Injection

MongoDB is one of the most popular NoSQL databases and is susceptible to various injection attacks:

JavaScript Injection

MongoDB allows JavaScript execution in certain operations. Attackers can inject malicious JavaScript code:

// Vulnerable code
db.users.find({ username: userInput });

// Malicious input: "; return true; //
// Results in: db.users.find({ username: ""; return true; // });

Operator Injection

MongoDB uses operators like $where, $ne, $gt, etc. Attackers can manipulate these:

// Vulnerable authentication check
db.users.find({
username: req.body.username,
password: req.body.password
});

// Malicious payload:
// username: "admin"
// password: { $ne: null }
// This bypasses password validation

CouchDB Injection

CouchDB uses JSON-based queries and can be vulnerable to:

// Vulnerable view query
function(doc) {
if (doc.type === 'user' && doc.name === userInput) {
emit(doc._id, doc);
}
}

// Malicious input can manipulate the view function

Real-World Attack Examples

Authentication Bypass

Consider a Node.js application with MongoDB:

// Vulnerable login function
app.post('/login', (req, res) => {
const { username, password } = req.body;

db.collection('users').findOne({
username: username,
password: password
}, (err, user) => {
if (user) {
res.json({ success: true, message: 'Login successful' });
} else {
res.json({ success: false, message: 'Invalid credentials' });
}
});
});

Attack payload:

{
"username": "admin",
"password": { "$ne": null }
}

This payload exploits the $ne (not equal) operator to bypass password validation.

Data Extraction

// Vulnerable search function
app.get('/search', (req, res) => {
const searchTerm = req.query.q;

db.collection('documents').find({
$where: `this.title.indexOf('${searchTerm}') !== -1`
}).toArray((err, docs) => {
res.json(docs);
});
});

Attack payload:

/search?q=') !== -1 || this.secret || ('

This manipulates the $where clause to potentially expose all documents.

JavaScript Code Execution

// Dangerous use of $where operator
db.users.find({
$where: `this.age > ${userAge}`
});

// Malicious input: "20; return true; //"
// Results in code execution outside the intended logic

Prevention Techniques

1. Input Validation and Sanitization

Always validate and sanitize user input:

const validator = require('validator');

// Validate input types
function validateInput(input) {
if (typeof input !== 'string') {
throw new Error('Invalid input type');
}

// Sanitize special characters
return validator.escape(input);
}

// Safe login function
app.post('/login', (req, res) => {
try {
const username = validateInput(req.body.username);
const password = validateInput(req.body.password);

db.collection('users').findOne({
username: username,
password: password
}, callback);
} catch (error) {
res.status(400).json({ error: 'Invalid input' });
}
});

2. Use Parameterized Queries

Avoid string concatenation in queries:

// BAD: String concatenation
const query = `{ "username": "${username}" }`;

// GOOD: Proper object construction
const query = { username: username };

3. Disable JavaScript Execution

For MongoDB, disable server-side JavaScript when not needed:

// MongoDB configuration
mongod --noscripting

// Or in code, avoid $where operator
// Use explicit field comparisons instead

4. Implement Proper Schema Validation

Use schema validation to restrict allowed data types:

// MongoDB schema validation
db.createCollection('users', {
validator: {
$jsonSchema: {
bsonType: 'object',
required: ['username', 'password'],
properties: {
username: {
bsonType: 'string',
description: 'must be a string and is required'
},
password: {
bsonType: 'string',
description: 'must be a string and is required'
}
}
}
}
});

5. Use Object-Document Mapping (ODM)

ODMs like Mongoose provide built-in protection:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
validate: {
validator: function(v) {
return /^[a-zA-Z0-9_]+$/.test(v);
},
message: 'Username contains invalid characters'
}
},
password: {
type: String,
required: true
}
});

const User = mongoose.model('User', userSchema);

// Safe query using Mongoose
User.findOne({
username: req.body.username,
password: req.body.password
});

Security Testing for NoSQL Injection

Automated Testing Tools

  1. NoSQLMap: A specialized tool for NoSQL injection testing
# Install NoSQLMap
git clone https://github.com/codingo/NoSQLMap.git
cd NoSQLMap
python nosqlmap.py -u "http://target.com/login" --data "username=admin&password=admin"
  1. Burp Suite: Professional web application security testing
    • Use Burp's Intruder to test various NoSQL injection payloads
    • Custom payload lists for NoSQL operators

Manual Testing Techniques

Test for Operator Injection

// Test payloads for authentication bypass
{
"username": "admin",
"password": { "$ne": null }
}

{
"username": "admin",
"password": { "$regex": ".*" }
}

{
"username": { "$gt": "" },
"password": { "$gt": "" }
}

Test for JavaScript Injection

// Payloads for $where operator
"'; return true; //"
"' || 1==1 //"
"' || this.password //"

Code Review Checklist

When reviewing code for NoSQL injection vulnerabilities:

  • Are user inputs directly concatenated into queries?
  • Is the $where operator used with user input?
  • Are query operators ($ne, $gt, etc.) filtered from user input?
  • Is input validation performed on all user data?
  • Are parameterized queries used consistently?
  • Is schema validation implemented?

Real-World Case Studies

Case Study 1: Authentication Bypass in E-commerce

A major e-commerce platform suffered a breach where attackers used NoSQL injection to bypass admin authentication:

Vulnerable code:

db.admins.findOne({
email: req.body.email,
password: req.body.password
});

Attack:

{
"email": "admin@company.com",
"password": { "$ne": null }
}

Impact: Complete admin panel access, customer data exposure

Fix: Implemented input type validation and used Mongoose ODM

Case Study 2: Data Extraction via JavaScript Injection

A social media application allowed profile searches that were vulnerable to JavaScript injection:

Vulnerable code:

db.profiles.find({
$where: `this.bio.includes('${searchTerm}')`
});

Attack:

searchTerm: "') || this.private_data || ('"

Impact: Exposure of private user data

Fix: Replaced $where with regex-based text search using $regex operator

Advanced Protection Strategies

Defense in Depth

Implement multiple layers of security:

  1. Network Level: Firewall rules, VPN access
  2. Application Level: Input validation, authentication
  3. Database Level: User permissions, query restrictions
  4. Monitoring Level: Anomaly detection, logging

Database Security Configuration

MongoDB Security Best Practices

// Enable authentication
use admin
db.createUser({
user: "admin",
pwd: "strongPassword",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
});

// Enable authorization
mongod --auth

// Bind to specific IP
mongod --bind_ip 127.0.0.1

// Enable SSL/TLS
mongod --sslMode requireSSL --sslPEMKeyFile /path/to/ssl.pem

Monitoring and Alerting

Implement monitoring for suspicious database activity:

// Example: Log suspicious query patterns
const suspiciousOperators = ['$where', '$ne', '$regex', '$gt'];

function logSuspiciousActivity(query) {
const queryString = JSON.stringify(query);

suspiciousOperators.forEach(operator => {
if (queryString.includes(operator)) {
console.warn(`Suspicious query detected: ${queryString}`);
// Send alert to security team
}
});
}

Tools and Resources

Security Testing Tools

  1. NoSQLMap: Automated NoSQL injection testing
  2. OWASP ZAP: Free security testing proxy
  3. Burp Suite: Professional web application testing
  4. MongoDB Compass: Query analysis and monitoring

Security Libraries

// Input validation
const Joi = require('joi');
const validator = require('validator');

// ODM/ORM protection
const mongoose = require('mongoose'); // MongoDB
const nano = require('nano'); // CouchDB

// Security middleware
const helmet = require('helmet');
const express = require('express');

const app = express();
app.use(helmet()); // Security headers
Best Practices Summary
  1. Never trust user input - Always validate and sanitize
  2. Use parameterized queries - Avoid string concatenation
  3. Implement proper authentication - Multi-factor when possible
  4. Regular security testing - Both automated and manual
  5. Keep databases updated - Apply security patches promptly
  6. Monitor database activity - Detect anomalies early
  7. Follow principle of least privilege - Minimal necessary permissions

Conclusion

NoSQL injection represents a significant security risk in modern applications. By understanding the attack vectors, implementing proper prevention techniques, and maintaining a security-first mindset, developers can protect their applications and data from these sophisticated attacks.

Remember that security is an ongoing process, not a one-time implementation. Regular testing, monitoring, and staying updated with the latest security practices are essential for maintaining a secure application environment.

Additional Resources