Skip to content

feat: add NoSQL injection skill#404

Open
sandiyochristan wants to merge 2 commits intousestrix:mainfrom
sandiyochristan:feat/nosql-injection-skill
Open

feat: add NoSQL injection skill#404
sandiyochristan wants to merge 2 commits intousestrix:mainfrom
sandiyochristan:feat/nosql-injection-skill

Conversation

@sandiyochristan
Copy link
Copy Markdown

Summary

The existing sql_injection skill 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/$regex operator 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.md

MongoDB coverage:

  • Operator injection ($ne, $gt, $regex, $in) for authentication bypass — both JSON body and bracket-notation form fields
  • Character-by-character blind extraction via $regex with binary search methodology
  • $where JavaScript injection with sleep()-based timing oracle (MongoDB < 4.4)
  • Aggregation pipeline injection into $match / $lookup stages
  • Mongoose {strict: false} and ODM wrapper identification

Additional NoSQL stores:

  • Redis: RESP protocol injection via \r\n command smuggling
  • Elasticsearch: Lucene query_string injection, Painless script injection via _update
  • DynamoDB: PartiQL filter expression injection
  • CouchDB: Mango query selector injection

Detection:

  • Error fingerprinting (MongoError, CastError, ValidationError)
  • Content-type and bracket-notation routing (Express body-parser behavior)
  • Operator probe patterns for all three input formats

Test Plan

  • Send {"username": {"$ne": null}, "password": {"$ne": null}} to a login endpoint — confirm bypass
  • Send bracket notation username[$ne]=invalid&password[$ne]=invalid in form body — confirm same bypass
  • Use $regex blind extraction to retrieve first character of a password hash or reset token
  • Confirm $where timing differential on a MongoDB < 4.4 target
  • Test Elasticsearch query_string with role:admin against a user search endpoint
  • Run make check-all

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 28, 2026

Greptile Summary

This PR adds strix/skills/vulnerabilities/nosql_injection.md, a new skill providing NoSQL injection testing guidance for MongoDB operator injection, blind extraction, $where JavaScript injection, and secondary stores (Redis, Elasticsearch, DynamoDB, CouchDB). The skill follows the established pattern of existing vulnerability skills and the MongoDB and Elasticsearch coverage is thorough and well-structured.

Two P1 issues need to be resolved before this is loaded into agent context:

  • $where version boundary is wrong and internally inconsistent: Line 105 says $where is "disabled by default in MongoDB 4.4+" but MongoDB 4.4 only deprecated the feature — it was not disabled by default until MongoDB 7.0. This conflicts directly with Pro Tip does this pollute the db at all or is it sandboxed? #3 (line 217), which says "$where is available and dangerous on pre-4.4," implying 4.4+ targets are safe. Together these two statements would cause an agent to skip $where testing on any MongoDB 4.4–6.x target.
  • Cassandra is claimed as a covered attack surface but has zero content: The introduction explicitly lists Cassandra as having a "distinct injection surface" but it appears nowhere else in the file — no Attack Surface entry, no example payload, no Pro Tip.

Confidence Score: 4/5

Safe to merge after fixing the MongoDB $where version boundary (7.0, not 4.4) and resolving the Cassandra coverage gap.

Two P1 findings exist: an incorrect version boundary that would cause agents to skip $where testing on MongoDB 4.4–6.x, and a false claim in the intro that Cassandra injection is covered. The rest of the skill is technically accurate and well-structured. Neither P1 requires a significant rewrite.

strix/skills/vulnerabilities/nosql_injection.md — specifically the $where section (line 105), Pro Tip #3 (line 217), and the introductory paragraph (line 8).

Important Files Changed

Filename Overview
strix/skills/vulnerabilities/nosql_injection.md New skill file providing NoSQL injection guidance; contains two P1 issues: an incorrect MongoDB version boundary for $where (states 4.4+ when it should be 7.0+) that also conflicts with Pro Tip #3, and a Cassandra promise in the intro that has zero coverage in the skill body.
Prompt To Fix All 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.

---

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:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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:

Suggested change
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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Comment on lines +107 to +108
{"$where": "function(){return this.username == 'admin' && sleep(2000)}"}
{"$where": "function(){return this.role == 'admin'}"}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 $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.:

Suggested change
{"$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.

Ahmex000 added a commit to Ahmex000/strix that referenced this pull request Mar 28, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant