high · 7.1Jul 24, 2026

Budibase MongoDB Integration NoSQL Operator Injection

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A BASIC app user in Budibase can override a builder-scoped MongoDB query filter by injecting MongoDB operators through an unescaped Handlebars binding, reading every document in the collection…

Package@budibase/server
Ecosystemnpm
Affected<= 3.38.1
Budibase MongoDB Integration NoSQL Operator Injection

The problem

Budibase's MongoDB integration enriches query JSON fields using Handlebars with noEscaping: true, then passes the result straight to JSON.parse. This means any " or } a user supplies lands verbatim in the parsed query object.

Builders commonly scope MongoDB reads per-user with a filter like {"email": "{{ currentUser.email }}"}. Because there is no parameterization step (SQL datasources go through interpolateSQL; MongoDB does not), a BASIC user can inject a MongoDB operator into the binding value and replace the builder's filter entirely.

The impact ranges from a full collection dump to arbitrary JavaScript execution via $where, cross-collection reads via $lookup, and full data wipe via injected update or delete filters.

Proof of concept

A working proof-of-concept for this issue in @budibase/server, with the exact payload below.

http
POST /api/queries/:queryId
Content-Type: application/json
x-budibase-app-id: <PROD_APP_ID>
Cookie: <BOB_SESSION>

{
  "parameters": {
    "name": "x\", \"name\": {\"$ne\": \"x\"}, \"$comment\": \"bud-033"
  }
}

# The builder's template {"name": "{{name}}"} enriches to:
# {"name": "x", "name": {"$ne": "x"}, "$comment": "bud-033"}
#
# Node's JSON.parse keeps the last value for the duplicate key "name",
# so the object reaching collection.find() is:
# { name: { $ne: "x" }, $comment: "bud-033" }
#
# $comment is a no-op meta operator that silently consumes the trailing
# quote+brace from the template. The effective filter matches every document.

The root cause is CWE-89 (operator injection). processStringSync is called with noEscaping: true, which is the Handlebars triple-brace mode: no HTML entity encoding, so special characters from user input survive into the string. JSON.parse then promotes those characters into real JSON structure, including operator keys prefixed with $.

The duplicate-key trick ("name" appears twice) is the bypass mechanism. ECMA-404 leaves duplicate-key behavior implementation-defined; V8 and Node keep the last value, so the injected operator object silently overwrites the builder's intended scalar value. createObjectIds, the only post-parse processing step in mongodb.ts, rewrites ObjectId(...) strings but does not strip $-prefixed keys, so the operator-shaped value reaches collection.find unchanged.

The fix in PR #18907 (commit dd8c065) sanitizes user-controlled parameter values before they can mutate query structure, mirroring the parameterized approach SQL datasources already use.

The fix

Upgrade @budibase/server to 3.39.9 or later (fixed in PR #18907, commit dd8c0654b35cd89ce3645f2355f4bf2ff9a5dd80). The patch strips operator keys from any object that originates from user-supplied parameters before it reaches the MongoDB driver. If you cannot upgrade immediately, audit every MongoDB query in your published apps and remove or restrict any query whose json body uses {{binding}} substitution inside a string value, as that is the vulnerable pattern.

Reported by aisafe.io.

References: [1][2][3][4][5]

Related research