NoSQL injection (CWE-943) is SQL injection's less-discussed cousin: instead of terminating a string and injecting SQL keywords, attackers inject MongoDB operators like $where, $gt, or $regex by submitting JSON objects where scalars are expected. OWASP API Security Top 10 2023 API10 (Unsafe Consumption of APIs) and OWASP A03 2021 (Injection) both cover this pattern. The attack is enabled by JavaScript's ...spread operator or Object.assign applied to user input before a findOne or find call — a common pattern when developers forward query parameters directly to database operations. The impact ranges from authentication bypass ({ password: { $gt: '' } } matches any password) to full document exfiltration.
Low because NoSQL injection requires the application to spread or merge user input directly into query objects, a pattern more common in older codebases than in typed ORM usage.
Never spread or merge user input into NoSQL query objects. Map only the specific fields you need by name, and validate types before they reach the database layer.
// Bad — spreads user input directly into MongoDB query
const user = await db.collection('users').findOne({ ...req.body })
// Bad — merges query params into filter without type checking
const results = await db.collection('posts').find({ ...req.query }).toArray()
// Good — explicit field extraction with type coercion
const { email, name } = req.body as Record<string, unknown>
if (typeof email !== 'string' || typeof name !== 'string') {
return res.status(400).json({ error: 'Invalid input' })
}
const user = await db.collection('users').findOne({ email, name })
In Mongoose or Prisma, typed schemas enforce field shapes and reject unknown operator keys automatically.
ID: api-security.abuse-prevention.nosql-safety
Severity: low
What to look for: Enumerate every relevant item. If the application uses NoSQL databases (MongoDB, DynamoDB, Firebase), check whether user input is safely merged into query objects or used with type-safe constructors. Unsafe patterns include directly merging user objects into query filters.
Pass criteria: At least 1 of the following conditions is met. NoSQL queries use type-safe methods or construct queries safely. User input is not directly merged into query objects.
Fail criteria: User input is directly merged into NoSQL query objects, allowing query injection attacks. Example: db.find({ ...userInput }) where userInput could contain { $where: ... }.
Skip (N/A) when: The application does not use NoSQL databases.
Detail on fail: "MongoDB queries merge user input directly into filter objects — NoSQL injection possible" or "Firebase queries use unsanitized user data in filter construction"
Remediation: Construct NoSQL queries safely:
// Bad: Direct merge
const user = await db.collection('users').findOne({ ...userInput })
// Good: Explicit field mapping
const user = await db.collection('users').findOne({
email: userInput.email,
name: userInput.name
})
// Good: ORM with validation
const user = await User.findOne({
email: userInput.email
})