← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

NoSQL Injection

Security CWE-943 OWASP A3:2021 CVSS 8.8 PHP 5.4+ Intermediate
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep and psalm — both specialist static analysis tools that must be configured to flag MongoDB collection methods called with unsanitised $_POST/$_GET input. This is not caught by a default linter or compiler; it requires intentional SAST tooling, but it is automatable once set up.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix is to type-cast every user-supplied value to its expected scalar type before use and reject inputs with '$'-prefixed keys. This is a small, localised change — a validation/casting layer at query-construction points — but it may touch several endpoints/query-building locations without being a full cross-cutting refactor.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The burden falls specifically on code paths that construct MongoDB/Redis queries from user input (web, cli, queue-worker contexts). It imposes a persistent review and discipline requirement on query-building code, but the rest of the codebase is largely unaffected. It does not reshape the entire system architecture.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field captures this precisely: developers confidently believe NoSQL databases are injection-immune because there is no SQL syntax. This contradicts how injection is understood in SQL contexts and leads developers to skip defences entirely. The operator injection vector ($ne, $gt, $where) is non-obvious and contradicts the 'no SQL, no injection' mental model most developers carry, making this a serious cognitive trap.

About DEBT scoring →

Also Known As

NoSQL injection MongoDB injection document store injection operator injection $where injection

TL;DR

Attacker-controlled input embedded into NoSQL queries (MongoDB, Redis, Couchbase) that subverts query intent — bypassing auth, exfiltrating data, or executing server-side code.

Explanation

NoSQL injection is the document-store equivalent of SQL injection, but with attack vectors specific to each engine. In MongoDB, the most common patterns are: operator injection where attacker input becomes a query operator object (e.g. submitting `{"$ne": null}` as a password to bypass a `find({user, password})` query); JavaScript injection via the `$where` operator or `mapReduce`, which executes attacker-controlled JS server-side; and array/object payload injection in fields the application expects to be strings. Redis vulnerabilities cluster around `EVAL`, `SCRIPT LOAD`, and command injection through unvalidated arguments to Lua scripts. Couchbase and other engines have N1QL injection that closely mirrors SQL injection. The unifying defence is the same as SQL: never concatenate untrusted input into queries; use parameterised query builders, type-cast inputs to expected scalar types before query construction, and validate that JSON inputs match a strict schema. PHP's MongoDB driver (`mongodb/mongodb`) accepts BSON arrays — type-casting `$_POST` values to strings before passing them to a query is a critical defensive step.

How It's Exploited

Login bypass: POST `username=admin&password[$ne]=x` — MongoDB matches any password where the field is not equal to 'x', returning the admin record. Data exfiltration: `username[$regex]=^a` — enumerate accounts character-by-character. RCE on `$where`: `username=admin'; sleep(5000); var x='` — server-side JS execution.

Watch Out

json_decode($input, true) returns associative arrays — passing the result into a query is the exact same vulnerability as passing $_POST directly. Type-cast and validate every field individually.

Common Misconception

NoSQL databases are immune to injection because they don't use SQL. They are not — they accept structured query objects, and any pathway that lets an attacker control the structure of those objects (not just the values) is an injection vector. Operator injection with `$ne`, `$gt`, or `$where` can bypass authentication or extract data without ever touching SQL syntax.

Why It Matters

PHP applications that pass `$_POST` values directly into MongoDB queries are routinely exploitable via JSON-encoded operator payloads. Authentication bypass is trivial — login forms that compare `find(['user' => $u, 'pass' => $p])` accept `pass[$ne]=` as a query-string payload that matches any password. Stored data exfiltration follows from there.

Common Mistakes

  • Passing `$_POST` arrays straight into MongoDB queries — PHP arrays serialize to BSON objects, turning user input into operator structure.
  • Using `$where` with concatenated user input — equivalent to executing attacker-controlled JavaScript server-side.
  • Assuming JSON parsing sanitises input — `json_decode` happily produces nested arrays that become query operators.
  • Treating Redis as injection-free — `EVAL` with concatenated arguments, or commands constructed from user input, are RCE-class vulnerabilities.
  • Filtering only string-keys without filtering values — operator injection happens through values that contain keys starting with `$`.

Avoid When

  • Code uses a typed query-builder with parameterised values and no raw arrays — validate that's actually the case before assuming safety.

When To Use

  • Reviewing any PHP code that builds MongoDB or Redis queries from request input.
  • Auditing authentication, search, and update endpoints in document-store applications.
  • Setting up CI rules to catch direct $_POST/$_GET use in query construction.

Code Examples

💡 Note
Casting to (string) is the minimal fix; production code should also validate input shape and use $eq explicitly when comparing user input to fields, never letting raw associative arrays reach the query.
✗ Vulnerable
// ❌ MongoDB query built from raw $_POST — accepts operator injection
$user = $collection->findOne([
    'username' => $_POST['username'],
    'password' => $_POST['password']
]);
// Attacker submits password[$ne]=x — matches any non-'x' password.
// Authentication bypass is one form post away.
✓ Fixed
// ✅ Cast to scalar string and validate — operator structure cannot survive
$username = (string) ($_POST['username'] ?? '');
$password = (string) ($_POST['password'] ?? '');

if ($username === '' || $password === '' || strlen($password) > 1024) {
    throw new InvalidArgumentException('Invalid credentials format');
}

$user = $collection->findOne([
    'username' => $username,
    'password' => password_verify_lookup($password)
]);

// For arbitrary user input that must be JSON, validate against a schema
// (e.g. opis/json-schema) before passing fields to the query builder.

Added 28 Apr 2026
Edited 12 Jun 2026
Views 38
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 0 pings S 0 pings S 3 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 1 ping T 0 pings W
No pings yet today
Bing 1
Perplexity 4 Google 3 Ahrefs 3 Bing 3 Scrapy 3 ChatGPT 2 Meta AI 2 Claude 1 SEMrush 1 Majestic 1 PetalBot 1
crawler 20 crawler_json 4
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Type-cast every user-supplied value to its expected scalar type (string, int) before placing it in a query array. Reject inputs whose JSON-decoded form contains keys starting with `$`.
📦 Applies To
PHP 5.4+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
MongoDB collection methods (findOne, find, updateOne) called with $_POST, $_GET, or json_decode result without type-casting
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: Low Context: Function Tests: Update
CWE-943 CWE-89


✓ schema.org compliant