feat: add NoSQL injection skill#404
Conversation
Add a new vulnerability skill covering NoSQL injection across MongoDB, Redis, Elasticsearch, DynamoDB, and CouchDB. The existing SQL injection skill covers relational databases only; NoSQL stores have fundamentally different injection models (operator injection, operator embedding, RESP protocol injection, Lucene query injection) that require separate guidance. Coverage: - MongoDB operator injection ($ne, $gt, $regex, $where, $expr) for authentication bypass and blind data extraction - Character-by-character $regex blind extraction of tokens and secrets - $where JavaScript injection with sleep-based timing oracle - Aggregation pipeline injection ($match, $lookup stage widening) - Redis RESP protocol injection via newline-delimited command smuggling - Elasticsearch query_string Lucene injection and Painless script injection - DynamoDB PartiQL filter expression injection - Bracket-notation form-body operator delivery (Express body-parser) - Bypass techniques: type coercion, encoding, operator alternatives Includes full detection flow, validation steps, and false-positive conditions (Mongoose strict mode, string casting middleware).
Greptile SummaryThis PR adds Two P1 issues need to be resolved before this is loaded into agent context:
Confidence Score: 4/5Safe to merge after fixing the MongoDB Two P1 findings exist: an incorrect version boundary that would cause agents to skip strix/skills/vulnerabilities/nosql_injection.md — specifically the Important Files Changed
Prompt To Fix All With AIThis is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 105
Comment:
**Incorrect MongoDB version boundary for `$where` — and internally inconsistent with Pro Tip #3**
Line 105 states `$where` is "disabled by default in MongoDB 4.4+", but MongoDB 4.4 only **deprecated** server-side JavaScript — it remained enabled by default. The `javascriptEnabled` parameter did not default to `false` until **MongoDB 7.0**. This matters because it causes testers to skip `$where` testing on MongoDB 4.4–6.x targets where the feature is still active.
This also directly contradicts **Pro Tip #3 (line 217)**, which says "`$where` is available and dangerous on pre-4.4" — implying 4.4+ is safe. The two statements give conflicting guidance:
| Location | Says |
|----------|------|
| Line 105 | "disabled by *default* in 4.4+" (implying it can be re-enabled on 4.4+) |
| Line 217 | "available and dangerous on pre-4.4" (implying 4.4+ is not a target) |
A tester following only Pro Tip #3 would miss every MongoDB 4.4–6.x deployment where JS is still active.
**Suggested fix for line 105:**
```suggestion
If `$where` operator is enabled (disabled by default in MongoDB 7.0+), inject arbitrary server-side JavaScript:
```
**And for line 217 (Pro Tip #3):**
```
3. Check MongoDB driver version via error messages; `$where` is active on pre-7.0 instances by default and still exploitable on 4.4–6.x targets where `javascriptEnabled` has not been explicitly set to false
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 8
Comment:
**Cassandra listed as a covered attack surface but never addressed**
The introduction explicitly calls out Cassandra as having a "distinct injection surface" alongside Redis, Elasticsearch, DynamoDB, and CouchDB:
> *"Redis, Elasticsearch, DynamoDB, **Cassandra**, and CouchDB each have distinct injection surfaces."*
However, Cassandra does not appear anywhere else in this file — it is absent from the Attack Surface section, Key Vulnerabilities, Testing Methodology, Pro Tips, and Summary. CQL injection (e.g., string concatenation into `SELECT`/`INSERT` statements via the Cassandra Query Language) is a real and distinct attack surface that was called out but never delivered.
An agent loading this skill would be told Cassandra has a unique injection model but given zero guidance on how to test it, creating a false sense of coverage.
Either remove "Cassandra" from the intro claim, or add a corresponding Attack Surface entry and at least a brief Key Vulnerability example (CQL injection via unparameterized `session.execute()` calls is the primary surface).
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 107-108
Comment:
**`$where` timing payload always returns falsy — potential confusion for testers**
The first example uses the `&&` short-circuit with `sleep()`:
```js
function(){ return this.username == 'admin' && sleep(2000) }
```
In JavaScript, `sleep()` returns `undefined` (falsy). So when `this.username == 'admin'` is `true`, the expression evaluates `sleep(2000)` (executing the delay on the server) but then returns `undefined`, which is falsy — meaning **the document is never selected**. This is a valid timing oracle (the delay reveals whether the condition matched), but it never returns any document in the result set.
The immediately following example on line 108 — `return this.role == 'admin'` — is a clean filter that *does* return matching documents, with no timing component.
Presenting them together without a comment distinguishing "timing-only oracle" from "direct filter" could confuse testers who expect the first payload to also return the matching document (and think it failed when it returns an empty result set with a noticeable delay).
Consider adding a brief clarifying note, e.g.:
```suggestion
{"$where": "function(){return this.username == 'admin' && sleep(2000)}"} // timing oracle only — never returns documents; observe response latency
{"$where": "function(){return this.role == 'admin'}"} // direct filter — returns matching documents
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: add NoSQL injection skill" | Re-trigger Greptile |
|
|
||
| ### `$where` JavaScript Injection | ||
|
|
||
| If `$where` operator is enabled (disabled by default in MongoDB 4.4+), inject arbitrary server-side JavaScript: |
There was a problem hiding this comment.
Incorrect MongoDB version boundary for
$where — and internally inconsistent with Pro Tip #3
Line 105 states $where is "disabled by default in MongoDB 4.4+", but MongoDB 4.4 only deprecated server-side JavaScript — it remained enabled by default. The javascriptEnabled parameter did not default to false until MongoDB 7.0. This matters because it causes testers to skip $where testing on MongoDB 4.4–6.x targets where the feature is still active.
This also directly contradicts Pro Tip #3 (line 217), which says "$where is available and dangerous on pre-4.4" — implying 4.4+ is safe. The two statements give conflicting guidance:
| Location | Says |
|---|---|
| Line 105 | "disabled by default in 4.4+" (implying it can be re-enabled on 4.4+) |
| Line 217 | "available and dangerous on pre-4.4" (implying 4.4+ is not a target) |
A tester following only Pro Tip #3 would miss every MongoDB 4.4–6.x deployment where JS is still active.
Suggested fix for line 105:
| If `$where` operator is enabled (disabled by default in MongoDB 4.4+), inject arbitrary server-side JavaScript: | |
| If `$where` operator is enabled (disabled by default in MongoDB 7.0+), inject arbitrary server-side JavaScript: |
And for line 217 (Pro Tip #3):
3. Check MongoDB driver version via error messages; `$where` is active on pre-7.0 instances by default and still exploitable on 4.4–6.x targets where `javascriptEnabled` has not been explicitly set to false
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 105
Comment:
**Incorrect MongoDB version boundary for `$where` — and internally inconsistent with Pro Tip #3**
Line 105 states `$where` is "disabled by default in MongoDB 4.4+", but MongoDB 4.4 only **deprecated** server-side JavaScript — it remained enabled by default. The `javascriptEnabled` parameter did not default to `false` until **MongoDB 7.0**. This matters because it causes testers to skip `$where` testing on MongoDB 4.4–6.x targets where the feature is still active.
This also directly contradicts **Pro Tip #3 (line 217)**, which says "`$where` is available and dangerous on pre-4.4" — implying 4.4+ is safe. The two statements give conflicting guidance:
| Location | Says |
|----------|------|
| Line 105 | "disabled by *default* in 4.4+" (implying it can be re-enabled on 4.4+) |
| Line 217 | "available and dangerous on pre-4.4" (implying 4.4+ is not a target) |
A tester following only Pro Tip #3 would miss every MongoDB 4.4–6.x deployment where JS is still active.
**Suggested fix for line 105:**
```suggestion
If `$where` operator is enabled (disabled by default in MongoDB 7.0+), inject arbitrary server-side JavaScript:
```
**And for line 217 (Pro Tip #3):**
```
3. Check MongoDB driver version via error messages; `$where` is active on pre-7.0 instances by default and still exploitable on 4.4–6.x targets where `javascriptEnabled` has not been explicitly set to false
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| # NoSQL Injection | ||
|
|
||
| NoSQL injection exploits the mismatch between how applications pass user input to database queries and how the database engine interprets that input. Unlike SQL injection, NoSQL injection frequently involves operator injection (e.g., MongoDB's `$gt`, `$regex`, `$where`) or structure injection (embedding JSON sub-documents). The attack surface is broad: MongoDB is the dominant target, but Redis, Elasticsearch, DynamoDB, Cassandra, and CouchDB each have distinct injection surfaces. |
There was a problem hiding this comment.
Cassandra listed as a covered attack surface but never addressed
The introduction explicitly calls out Cassandra as having a "distinct injection surface" alongside Redis, Elasticsearch, DynamoDB, and CouchDB:
"Redis, Elasticsearch, DynamoDB, Cassandra, and CouchDB each have distinct injection surfaces."
However, Cassandra does not appear anywhere else in this file — it is absent from the Attack Surface section, Key Vulnerabilities, Testing Methodology, Pro Tips, and Summary. CQL injection (e.g., string concatenation into SELECT/INSERT statements via the Cassandra Query Language) is a real and distinct attack surface that was called out but never delivered.
An agent loading this skill would be told Cassandra has a unique injection model but given zero guidance on how to test it, creating a false sense of coverage.
Either remove "Cassandra" from the intro claim, or add a corresponding Attack Surface entry and at least a brief Key Vulnerability example (CQL injection via unparameterized session.execute() calls is the primary surface).
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 8
Comment:
**Cassandra listed as a covered attack surface but never addressed**
The introduction explicitly calls out Cassandra as having a "distinct injection surface" alongside Redis, Elasticsearch, DynamoDB, and CouchDB:
> *"Redis, Elasticsearch, DynamoDB, **Cassandra**, and CouchDB each have distinct injection surfaces."*
However, Cassandra does not appear anywhere else in this file — it is absent from the Attack Surface section, Key Vulnerabilities, Testing Methodology, Pro Tips, and Summary. CQL injection (e.g., string concatenation into `SELECT`/`INSERT` statements via the Cassandra Query Language) is a real and distinct attack surface that was called out but never delivered.
An agent loading this skill would be told Cassandra has a unique injection model but given zero guidance on how to test it, creating a false sense of coverage.
Either remove "Cassandra" from the intro claim, or add a corresponding Attack Surface entry and at least a brief Key Vulnerability example (CQL injection via unparameterized `session.execute()` calls is the primary surface).
How can I resolve this? If you propose a fix, please make it concise.| {"$where": "function(){return this.username == 'admin' && sleep(2000)}"} | ||
| {"$where": "function(){return this.role == 'admin'}"} |
There was a problem hiding this comment.
$where timing payload always returns falsy — potential confusion for testers
The first example uses the && short-circuit with sleep():
function(){ return this.username == 'admin' && sleep(2000) }In JavaScript, sleep() returns undefined (falsy). So when this.username == 'admin' is true, the expression evaluates sleep(2000) (executing the delay on the server) but then returns undefined, which is falsy — meaning the document is never selected. This is a valid timing oracle (the delay reveals whether the condition matched), but it never returns any document in the result set.
The immediately following example on line 108 — return this.role == 'admin' — is a clean filter that does return matching documents, with no timing component.
Presenting them together without a comment distinguishing "timing-only oracle" from "direct filter" could confuse testers who expect the first payload to also return the matching document (and think it failed when it returns an empty result set with a noticeable delay).
Consider adding a brief clarifying note, e.g.:
| {"$where": "function(){return this.username == 'admin' && sleep(2000)}"} | |
| {"$where": "function(){return this.role == 'admin'}"} | |
| {"$where": "function(){return this.username == 'admin' && sleep(2000)}"} // timing oracle only — never returns documents; observe response latency | |
| {"$where": "function(){return this.role == 'admin'}"} // direct filter — returns matching documents |
Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/skills/vulnerabilities/nosql_injection.md
Line: 107-108
Comment:
**`$where` timing payload always returns falsy — potential confusion for testers**
The first example uses the `&&` short-circuit with `sleep()`:
```js
function(){ return this.username == 'admin' && sleep(2000) }
```
In JavaScript, `sleep()` returns `undefined` (falsy). So when `this.username == 'admin'` is `true`, the expression evaluates `sleep(2000)` (executing the delay on the server) but then returns `undefined`, which is falsy — meaning **the document is never selected**. This is a valid timing oracle (the delay reveals whether the condition matched), but it never returns any document in the result set.
The immediately following example on line 108 — `return this.role == 'admin'` — is a clean filter that *does* return matching documents, with no timing component.
Presenting them together without a comment distinguishing "timing-only oracle" from "direct filter" could confuse testers who expect the first payload to also return the matching document (and think it failed when it returns an empty result set with a noticeable delay).
Consider adding a brief clarifying note, e.g.:
```suggestion
{"$where": "function(){return this.username == 'admin' && sleep(2000)}"} // timing oracle only — never returns documents; observe response latency
{"$where": "function(){return this.role == 'admin'}"} // direct filter — returns matching documents
```
How can I resolve this? If you propose a fix, please make it concise.Replace minimal nosql_injection.md with comprehensive version from usestrix#404 covering MongoDB operator injection, Redis/Elasticsearch/DynamoDB attack surfaces, blind extraction, bypass techniques, and validation methodology.
…sandra CQL injection Three reviewer findings addressed: P1 — $where version boundary: corrected from 'disabled by default in MongoDB 4.4+' to 'disabled by default in MongoDB 7.0+'. MongoDB 4.4 deprecated server-side JavaScript but left javascriptEnabled defaulting to true; the feature was not disabled by default until 7.0. The section now explicitly notes that 4.4-6.x targets are still exploitable unless explicitly hardened. P1 — Pro Tip usestrix#3: updated to match the corrected version boundary. Previous text 'available and dangerous on pre-4.4' contradicted the main section and would cause testers to skip $where on 4.4-6.x. Now states 'active by default on pre-7.0 instances, including 4.4-6.x'. P1 — Cassandra coverage gap: the introduction claimed Cassandra as a covered attack surface but the skill body had no Cassandra content. Added Cassandra to the Attack Surface section (CQL injection, ALLOW FILTERING predicates, UDF injection) and added a Cassandra CQL Injection subsection in Key Vulnerabilities covering string concatenation injection, authentication bypass, and boolean extraction.
Summary
The existing
sql_injectionskill covers relational databases (MySQL, PostgreSQL, MSSQL, Oracle). NoSQL stores have fundamentally different injection models — operator injection, structure injection, RESP protocol injection, and Lucene query injection — requiring separate guidance. MongoDB alone powers a significant portion of modern web backends, and its$ne/$gt/$regexoperator injection bypassing authentication is one of the most consistently findable vulnerabilities in Node.js stacks.This PR adds
strix/skills/vulnerabilities/nosql_injection.md.What's Added
New file:
strix/skills/vulnerabilities/nosql_injection.mdMongoDB coverage:
$ne,$gt,$regex,$in) for authentication bypass — both JSON body and bracket-notation form fields$regexwith binary search methodology$whereJavaScript injection withsleep()-based timing oracle (MongoDB < 4.4)$match/$lookupstages{strict: false}and ODM wrapper identificationAdditional NoSQL stores:
\r\ncommand smugglingquery_stringinjection, Painless script injection via_updateDetection:
MongoError,CastError,ValidationError)body-parserbehavior)Test Plan
{"username": {"$ne": null}, "password": {"$ne": null}}to a login endpoint — confirm bypassusername[$ne]=invalid&password[$ne]=invalidin form body — confirm same bypass$regexblind extraction to retrieve first character of a password hash or reset token$wheretiming differential on a MongoDB < 4.4 targetquery_stringwithrole:adminagainst a user search endpointmake check-all