← Alle Neuigkeiten
security4 Min. Lesezeit

NoSQL injection in AI-generated MongoDB queries

Von Seaworthy · 28. Juni 2026

Red padlock resting on a black computer keyboard, symbolising access control and cybersecurity

Photo by FlyD on Unsplash

The problem with generated query code

When developers use AI to write MongoDB queries, they get code that works. It connects to the database and returns results. The smoke test passes. But there's a category of bug that smoke tests don't catch: injection vulnerabilities baked into the query logic itself.

MongoDB is not SQL, so the assumption is that SQL injection doesn't apply. It doesn't. NoSQL injection does. And AI models, trained on code that routinely skips input sanitization, are good at generating query patterns that open the door to authentication bypass and arbitrary JavaScript execution.

$where and the JavaScript problem

MongoDB's $where operator lets you filter documents using a JavaScript expression evaluated server-side. It's available in most MongoDB deployments and it's dangerous. Here's what AI-generated login code sometimes looks like:

// Vulnerable: user input interpolated directly into $where
async function findUser(username, password) {
  return db.collection('users').findOne({
    $where: `this.username === '${username}' && this.password === '${password}'`
  });
}

An attacker submitting ' || '1'=='1 as the username gets a JavaScript expression that evaluates to true for every document in the collection. The first document returned is usually an admin account. No special tools required.

The AI that generated this didn't flag it. The code passes a basic test with real credentials. It ships.

$where runs JavaScript server-side, which means the attacker can do more than bypass a condition. In sufficiently unguarded environments they can use sleep() calls to confirm injection blindly, or extract data character by character. The attack surface is larger than a simple authentication bypass.

Operator injection: quieter but just as bad

$where gets attention. Operator injection is less well-known, and AI models produce it constantly.

When a web framework passes a JSON body directly into a MongoDB query without type checking, the attacker controls the query structure, not just the values. Consider this:

// Vulnerable: req.body passed directly to findOne
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = await db.collection('users').findOne({ username, password });
  if (user) return res.json({ token: generateToken(user) });
  return res.status(401).json({ error: 'Invalid credentials' });
});

This looks reasonable. But if the attacker sends:

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

MongoDB receives { username: "admin", password: { $gt: "" } }. Every stored password is "greater than" an empty string. Authentication is bypassed without any JavaScript or unusual technique. Just a JSON object where a string was expected.

AI tools almost never add type validation here. They write what you asked for: check if the username and password match. They assume the incoming values are strings.

What the fix looks like

The fix involves two things: validate input types before they reach the query layer, and never pass user-controlled values directly into query construction.

// Safer: type validation + password checked in application code
import { createHash, timingSafeEqual } from 'crypto';

app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  // Reject anything that isn't a plain string
  if (typeof username !== 'string' || typeof password !== 'string') {
    return res.status(400).json({ error: 'Invalid input' });
  }

  // Look up by username only; never query on the password field directly
  const user = await db.collection('users').findOne({ username });
  if (!user) return res.status(401).json({ error: 'Invalid credentials' });

  const stored = Buffer.from(user.passwordHash, 'hex');
  const supplied = Buffer.from(
    createHash('sha256').update(password).digest('hex'),
    'hex'
  );

  if (!timingSafeEqual(stored, supplied)) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  return res.json({ token: generateToken(user) });
});

The password field never reaches MongoDB. Type validation rejects operator objects before they get near the database. The comparison uses timingSafeEqual to avoid leaking timing information.

You should also consider disabling server-side JavaScript entirely. Setting security.javascriptEnabled: false in your MongoDB config removes $where as an attack surface. If you're on Atlas, check whether JavaScript execution is enabled for your cluster and turn it off if you're not using it.

Why AI makes this worse

AI code generation works by predicting plausible code. Plausible is not secure.

The training data includes tutorial-grade examples and documentation that skips validation to focus on syntax, plus Stack Overflow answers written before these patterns were widely understood. None of that code had to survive a production security review.

When you ask an AI to write a MongoDB authentication function, it finds the most common pattern. The most common pattern is the vulnerable one. It won't warn you. It will generate something that works fine in local testing, where you always send well-formed strings.

This is a structural problem. The code that gets committed and passes review is often the code that got shipped, not the code that got hardened. AI models learn from what humans actually wrote, not from what a security engineer would have written.

The feedback loop compounds it. A developer who doesn't know about operator injection won't recognize the bug when an AI generates it. They'll accept the suggestion and move on.

What to do

Validate input types before they touch the database. Libraries like zod make this explicit and auditable. If a field should be a plain string, assert that it is one before the MongoDB driver ever sees it.

Avoid $where entirely. There's always a better query approach using standard comparison operators. If you're reaching for $where, the query almost certainly needs to be split into a database lookup and an application-level filter.

Be skeptical of AI-generated database code in ways you might not be for other code. The generated function that connects and runs might be quietly skipping validation that a careful review would catch.

Seaworthy's static analysis checks MongoDB configuration as part of its ops basics category and can identify query construction patterns that pass unsanitized user input directly to the database layer.

Dieser Artikel wurde von KI generiert und fasst öffentlich verfügbare Quellen zusammen.

Von den Machern von Seaworthy

Seaworthy scannt dein Repository nach den Problemen, die in Artikeln wie diesem behandelt werden.

Sicherheitslücken, offengelegte Geheimnisse und Fehlkonfigurationen — erkannt, bevor du bereitstellst. Kostenlos, kein Konto nötig.

$ npx seaworthycode