All vulnerabilities
HighA03:2021CWE-943Injection

NoSQL Injection

NoSQL injection manipulates MongoDB, Firebase, and other NoSQL database queries by injecting operator objects, bypassing authentication and exposing all records.

What Is NoSQL Injection?

NoSQL injection targets applications using non-relational databases like MongoDB, CouchDB, or Firebase Firestore. Instead of SQL syntax, attackers inject JavaScript operators or query objects to manipulate the database query logic, bypassing authentication or exfiltrating data.

How It Works

A MongoDB login endpoint:

// Vulnerable — user-controlled JSON merged directly into query
app.post("/login", async (req, res) => {
  const { username, password } = req.body
 
  const user = await db.collection("users").findOne({
    username: username,
    password: password,  // Attacker can make this a query operator
  })
 
  if (user) return res.json({ token: generateToken(user) })
  res.status(401).json({ error: "Invalid credentials" })
})

The attacker sends:

{
  "username": "admin",
  "password": { "$ne": null }
}

The query becomes:

db.users.findOne({ username: "admin", password: { $ne: null } })

$ne: null means "password is not null" — which is true for every user. The attacker logs in as admin without knowing the password.

Exfiltration with $regex:

{ "password": { "$regex": "^a" } }

By iterating through regex patterns, attackers can extract passwords character by character.

Real-World Impact

  • Authentication bypass — log in as any user without credentials
  • Data enumeration — extract all documents using $regex or $where
  • Full collection dump — operators like $gt: "" match all documents
  • JavaScript injection$where operator executes arbitrary JS in MongoDB

How to Fix

Validate and sanitize input — reject operator objects:

def sanitize_mongo_input(value):
    if isinstance(value, dict):
        raise ValueError("Object input not allowed")
    if isinstance(value, str) and value.startswith("$"):
        raise ValueError("Operator input not allowed")
    return value
 
username = sanitize_mongo_input(request.json.get("username"))
password = sanitize_mongo_input(request.json.get("password"))

Use a schema validation library (Pydantic, Joi, Zod):

from pydantic import BaseModel
 
class LoginRequest(BaseModel):
    username: str  # Pydantic enforces string type — rejects objects
    password: str
 
@app.post("/login")
async def login(body: LoginRequest):
    user = await db.users.find_one({"username": body.username, "password": body.password})

Avoid $where entirely — it evaluates JavaScript and is inherently dangerous.

Use bcrypt for passwords — store hashes, not plaintext, so regex extraction is useless.

What VibeWShield Detects

VibeWShield injects MongoDB operator payloads ($ne, $gt, $regex, $where) into JSON request bodies and URL parameters. It looks for authentication bypass (unexpected 200 responses) and data exposure patterns in responses.

#nosql#mongodb#injection#database

Free security scan

Test your app for NoSQL Injection

VibeWShield automatically checks for NoSQL Injection and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.

Scan your app free