FlawOpen

flawopen.com/Reference/MongoDB NoSQL Injection

MongoDB NoSQL Injection: when input changes a query

Database Security Guide

MongoDB does not execute SQL, so SQL-string concatenation is not the issue. An application can still create a NoSQL injection flaw when it accepts an untrusted nested object where it expects a scalar and passes that object into a MongoDB filter. This is an application input-validation bug, not a MongoDB server CVE.

Plain English: a value becomes a rule

Imagine a form asks for a person’s name, but the clerk accepts a whole set of filing instructions in that box. The database then follows the instructions instead of comparing one name. Validate that the box contains the expected kind of value, and build the search rule yourself.

The trust boundary: request JSON to MongoDB filter

Query filter
A BSON document that MongoDB interprets as field comparisons and, when explicitly present, query operators.
Operator injection
An application passes attacker-controlled structure into a filter position where it intended one literal value.
Scalar validation
Checking the input type, length, and allowed format before it can influence a database operation.
Projection
A server-selected list of fields returned from a query, which limits accidental data exposure.

How the failure happens

1

The endpoint expects a scalar

The API contract says a field such as username is one string, but a JSON parser can represent strings, arrays, objects, booleans, and null.

2

The application skips type validation

The handler inserts the parsed value directly into a server-created filter, so an object remains structured query data rather than being treated as a literal string.

3

MongoDB evaluates the supplied structure

If the nested document contains query-operator structure, the predicate can mean something different from the intended exact-value comparison. The affected records depend on the query and the application’s authorization checks.

4

The response determines the exposure

Returned fields and record counts depend on projection, endpoint behavior, and the database account’s privileges. This does not by itself prove authentication bypass or database-wide access.

Scope and evidence

MongoDB’s official driver guidance documents this boundary when an endpoint converts unvalidated JSON to BSON and uses it as a filter. This guide models that application-level failure. It does not claim every MongoDB deployment is vulnerable, identify a server CVE, or provide an authentication-bypass recipe.

Vulnerable and hardened Node.js patterns

VULNERABLE — UNVALIDATED VALUE ENTERS FILTER
app.post("/users/lookup", async (req, res, next) => {
  try {
    // The route expects a string, but req.body.username is untrusted JSON.
    const user = await users.findOne({ username: req.body.username });
    res.json(user ? { username: user.username } : null);
  } catch (error) {
    next(error);
  }
});
HARDENED — VALIDATE SHAPE, BUILD FILTER, VERIFY HASH
const loginSchema = z.object({
  username: z.string().trim().min(1).max(128),
  password: z.string().min(1).max(1024)
}).strict();

app.post("/login", async (req, res, next) => {
  try {
    const parsed = loginSchema.safeParse(req.body);
    if (!parsed.success) return res.sendStatus(400);

    const { username, password } = parsed.data;
    // The application owns the filter key; input supplies only a string value.
    const user = await users.findOne(
      { username },
      { projection: { _id: 1, username: 1, passwordHash: 1 } }
    );
    const passwordMatches = user &&
      await argon2.verify(user.passwordHash, password);
    if (!passwordMatches) return res.sendStatus(401);

    return res.sendStatus(204); // Session creation is application-specific.
  } catch (error) {
    next(error);
  }
});

The hardened path rejects non-string fields before database access, accepts no client-supplied filter object, constructs a fixed filter key in application code, returns only selected fields, and verifies a password hash after looking up the user. The snippet assumes z is Zod, users is the MongoDB collection, and argon2 is a configured password-hashing library; session handling is intentionally outside the example.

Verification checks for the fix

Primary sources

Explore related security guides:Open the security directory →
See also SQL Injection (CWE-89): How It Works and How to Prevent It in Every Language — flawopen.com Why String Formatting Risks Numeric ID Queries What Is a Parameterized Query? Is Prisma $queryRaw Safe from SQL Injection? Is Rails where() String Interpolation Safe? Is Sequelize query() Safe from SQL Injection? Is SQLAlchemy text() Safe from SQL Injection?