Budibase MongoDB Integration NoSQL Operator Injection
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…

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.
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.
Related research
- critical · 9.6Budibase MySQL Integration SQL Injection via multipleStatements
- high · 7.6Budibase MySQL DESCRIBE Backtick Injection via multipleStatements
- critical · 10CVE-2026-54350CVE-2026-54350: @budibase/server Anonymous NoSQL Operator Injection via Query Templates
- high · 8.8Budibase: App-Scoped Builder Privilege Escalation via Public Role Assignment API