API Security

NoSQL Injection in APIs: Detection and Prevention

Key takeaways

NoSQL databases power the backend of most modern APIs, and MongoDB alone accounts for the majority of document-database deployments in production. The flexibility that makes NoSQL attractive, schema-less structures, JSON-native queries, and dynamic typing, also makes APIs built on top of these databases vulnerable to injection. Unlike Structured Query Language (SQL) injection, NoSQL injection does not require a single quote or a UNION statement. Attackers inject MongoDB operators like $ne, $gt, and $regex directly through JSON request bodies that APIs accept by design. The Verizon Data Breach Investigations Report found that web application attacks accounted for 12% of all confirmed breaches, and injection remains a core attack vector across both SQL and NoSQL databases.

What Is NoSQL Injection in APIs?

NoSQL injection occurs when an attacker manipulates database queries by inserting malicious operators or expressions into user input that a NoSQL database processes without validation. SQL injection exploits string concatenation in query construction. NoSQL injection exploits the flexible, JSON-based query structures that NoSQL databases accept natively.

APIs are especially vulnerable because the input format attackers need, JSON, is the same format APIs already accept in request bodies. No encoding or format conversion is required. An attacker sends a JSON payload with embedded MongoDB operators, and if the API passes that payload to the database without sanitization, the operators execute as part of the query.

How NoSQL Injection Works in an API Endpoint

A vulnerable Node.js Express endpoint that passes user input directly to a MongoDB query:

app.post('/api/login', (req, res) => { const { username, password } = req.body; db.collection('users').findOne({ username: username, password: password }, (err, user) => { if (user) { res.json({ message: "Login successful", token: generateToken(user) }); } else { res.status(401).json({ message: "Invalid credentials" }); } }); });

An attacker sends the following JSON body:

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

The $ne (not equal) operator turns the password check into "find a user where password is not equal to an empty string," which matches the admin account regardless of the actual password. Authentication is bypassed with a single API call. A successful exploit leads directly to sensitive data exposure, leaking user records, tokens, and internal data.

API-Specific Injection Surfaces

NoSQL injection in APIs reaches the database through channels that web form scanners do not cover:

  • JSON request bodies. POST and PUT endpoints accept structured JSON. Operators like $ne, $gt, $regex, and $where embed directly into JSON fields without any special encoding.
  • Query string parameters. GET requests can carry operator syntax through bracket notation: ?username[$ne]=&password[$ne]= bypasses authentication on endpoints that parse query strings into objects.
  • GraphQL variables. GraphQL APIs accept variables in JSON that resolve into database queries. A variable like {"userId": {"$gt": ""}} matches all records when the resolver passes input to MongoDB unvalidated.
  • HTTP headers. Custom headers used for tenant routing or user identification (X-User-ID, X-Tenant) can carry operator payloads when values flow into database queries.

The Open Web Application Security Project (OWASP) API Security Top 10 classifies injection risks under API8:2023 (Security Misconfiguration), where missing input validation enables NoSQL injection alongside SQL injection and command injection.

How to Detect NoSQL Injection in APIs

Detection requires testing every input channel with NoSQL-specific payloads. Standard SQL injection scanners miss NoSQL vulnerabilities entirely because the attack syntax is completely different.

Test with Operator Injection Payloads

Inject MongoDB operators into each parameter and observe the API response:

  • Authentication bypass. Send {"username": "admin", "password": {"$ne": ""}} to login endpoints. A successful login confirms that the API passes operators directly to the database.
  • Data enumeration. Send {"username": {"$gt": ""}} to list endpoints. An API returning all user records instead of one confirms operator injection.
  • Regex extraction. Send {"password": {"$regex": "^a"}} to determine if the password starts with "a." Iterating through characters reconstructs complete values one position at a time.
  • Existence checks. Send {"password": {"$exists": true}} to confirm whether specific fields exist in the database schema.

Test with JavaScript Injection Payloads

MongoDB's $where operator evaluates server-side JavaScript. If the API processes $where, attackers gain far more control:

  • Boolean extraction. Send {"$where": "this.username == 'admin' && this.password[0] == 'a'"} to extract the first character of the admin password.
  • Timing-based detection. Send {"$where": "sleep(5000)"} in any input field. A 5-second delay in the API response confirms JavaScript execution on the database server.

Fuzz API-Specific Input Channels

  • Fuzz JSON body fields with MongoDB operators ($ne, $gt, $lt, $regex, $in, $where, $exists) wrapped in nested objects.
  • Test query string bracket notation: ?field[$ne]=value, ?field[$regex]=^pattern, ?field[$gt]=.
  • Send operators through HTTP headers when custom headers feed into database queries.
  • An API fuzzing guide covers automated payload generation for both SQL and NoSQL targets.

Inspect Error Responses for Database Leakage

  • Send malformed operators like {"username": {"$invalid": true}} and examine the API response. A verbose error message containing "unknown operator" or "MongoError" confirms the API passes input directly to MongoDB and reveals the database type.
  • Submit mismatched data types, such as sending an object where the API expects a string. A response containing stack traces, query details, or field names exposes the internal database structure and confirms that input validation is missing.
  • Check whether error responses differ between valid operators used incorrectly ({"username": {"$regex": "[invalid"}}) and completely invalid input. Distinct error patterns reveal how deep user input travels into the query pipeline.

Test Content-Type Switching on Endpoints

  • Switch the Content-Type header from application/x-www-form-urlencoded to application/json on endpoints that originally accept form data. Many API frameworks automatically parse JSON bodies when the header changes, allowing operator injection on endpoints that were never designed to accept JSON input.
  • Send the same operator payload in both formats and compare responses. A login endpoint rejecting {"$ne": ""} as form data but accepting the same operator as a JSON body confirms inconsistent input handling across content types.
  • Test multipart/form-data endpoints with JSON-encoded field values. An API processing file uploads or form submissions may parse embedded JSON strings in individual fields without sanitization, creating an injection path that content-type-specific scanners overlook.

How to Prevent NoSQL Injection in APIs

Every detection technique above succeeds because user input reaches a NoSQL query as an executable operator. Prevention strips that capability at each layer. The API security checklist covers a full framework. Here are the specific steps to eliminate NoSQL injection from your APIs:

Step 1: Sanitize All Input with a Dedicated Library

Use mongo-sanitize or a similar library to strip MongoDB operators from user input before the input reaches any query. The secure version of the vulnerable login endpoint:

const sanitize = require('mongo-sanitize');

app.post('/api/login', (req, res) => { const username = sanitize(req.body.username); const password = sanitize(req.body.password); db.collection('users').findOne({ username: username, password: password }, (err, user) => { if (user) { res.json({ message: "Login successful", token: generateToken(user) }); } else { res.status(401).json({ message: "Invalid credentials" }); } }); });

mongo-sanitize strips any key starting with $ from the input object, preventing operator injection regardless of payload complexity.

Step 2: Cast Inputs to Expected Types

If a field should be a string, explicitly cast the input before using the value in a query. Operators like $ne and $gt only work when the input is an object. Casting to a string neutralizes them:

const username = String(req.body.username); const password = String(req.body.password);

Type casting is the simplest defense and should be applied even when sanitization libraries are in place.

Step 3: Disable Server-Side JavaScript Execution

MongoDB's $where operator evaluates JavaScript on the database server. Disable JavaScript execution entirely by setting javascriptEnabled: false in the MongoDB configuration file (mongod.conf). If $where is not needed for application logic, removing the attack surface eliminates JavaScript injection completely.

Step 4: Apply Least-Privilege Database Accounts

Connect each API service to MongoDB with a dedicated account that has only the permissions the service requires. A read-only endpoint should use a database user restricted to find operations. Separate accounts per microservice limit blast radius if injection succeeds.

Step 5: Integrate Automated Testing into CI/CD

New API endpoints and schema changes can reintroduce NoSQL injection flaws with every release. Automated API security testing in Continuous Integration/Continuous Deployment (CI/CD) pipelines catches regressions before code reaches production. Automated scanning generates operator injection payloads across every parameter on every build, covering what manual testing cannot match at scale.

Secure Your APIs Against NoSQL Injection

NoSQL injection in APIs is dangerous because the attack format, JSON with embedded operators, is the same format APIs accept natively. Sanitization libraries strip malicious operators at the input layer. Type casting neutralizes object-based payloads. Disabling server-side JavaScript eliminates $where exploitation entirely. Least-privilege database accounts contain the damage if any layer fails.

APIsec scans every API endpoint for NoSQL injection, operator injection, OWASP API Top 10 vulnerabilities, and business logic errors, catching what legacy scanners miss.

Start a free scan
and find out what your current tools are not detecting.

FAQs

What is NoSQL injection?

NoSQL injection is a vulnerability where attackers insert malicious operators or expressions into input that a NoSQL database executes. Unlike SQL injection, NoSQL injection exploits JSON-based query structures rather than string concatenation.

How is NoSQL injection different from SQL injection?

SQL injection inserts malicious SQL statements into string-concatenated queries. NoSQL injection inserts database operators ($ne, $gt, $regex) into JSON-based queries. The attack format, payload syntax, and detection methods are completely different.

Does the OWASP API Top 10 cover NoSQL injection?

NoSQL injection falls under API8:2023 (Security Misconfiguration) in the OWASP API Security Top 10. Injection risks are also addressed through unsafe data consumption (API10:2023).

Can a Web Application Firewall stop NoSQL injection in APIs?

WAFs can block known operator patterns in query strings, but often miss operators embedded in JSON request bodies. Input sanitization with libraries like mongo-sanitize at the application layer remains the primary defense.

What tools help detect NoSQL injection in APIs?

nosqlmap automates NoSQL injection detection across MongoDB, CouchDB, and Redis. For continuous coverage across all API endpoints, automated API security platforms generate operator injection payloads on every CI/CD build.