CVE-2026-73617
Budibase before 3.40.0 NoSQL Injection via MongoDB datasource
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
7.1
Budibase before 3.40.0 NoSQL Injection via MongoDB datasource
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
- Record
CVE-2026-73617- CVSS 4.0
- 7.1 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N - CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N - Weakness
- CWE-943
- Updated
- 2026-11-02
EUVDEUVD-2026-57821
7.1
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
- Record
EUVD-2026-57821- CVSS 4.0
- 7.1 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-pmpg-2mxq-6xwr
7.1
Budibase: NoSQL injection in MongoDB integration: collection dump, $where JS exec, cross-collection pivot, arbitrary update/delete
Summary
An end-user injection in Budibase's MongoDB datasource lets any BASIC app user bypass the builder's query-level access controls. Builders scope MongoDB reads per-user with bindings like {"email": "{{ currentUser.email }}"} so each app user only sees their own rows. Because the binding is handlebars-enriched into the query JSON with noEscaping: true and then JSON.parsed, Bob (a BASIC user) overrides the builder's filter with a MongoDB operator and reads every document the connection can touch. SQL datasources are parameterized through interpolateSQL(); the MongoDB path has no equivalent, so the scoping pattern Budibase's own docs show is unsafe.
Details
Enrichment
packages/server/src/sdk/workspace/queries/queries.ts:105-125 enriches every string field of the query with handlebars, then parses the enriched json field:
enrichedQuery[key] = processStringSync(fields[key], parameters, {
noEscaping: true,
noHelpers: true,
escapeNewlines: true,
})
// ...
enrichedQuery.json = JSON.parse(
enrichedQuery.json || enrichedQuery.customData || enrichedQuery.requestBody
)
noEscaping: true turns {{name}} into {{{name}}}, which Handlebars renders without HTML-escaping. Any " or } the attacker supplies lands verbatim in the enriched string. JSON.parse then produces a structured object whose top-level keys and operators came from the parameter value.
Execution
packages/server/src/integrations/mongodb.ts:499-512:
async read(query: MongoDBQuery) {
try {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
let json = this.createObjectIds(query.json)
switch (query.extra.actionType) {
case "find": {
if (json) {
return await collection.find(json).toArray()
}
createObjectIds walks the object and rewrites strings that look like ObjectId(...). It does not strip $-prefixed keys and does not reject operator-shaped values. The injected filter reaches collection.find unchanged.
For comparison, SQL datasources go through interpolateSQL at packages/server/src/threads/query.ts:145, which parameterizes bindings into driver-level bind variables. The MongoDB path has no equivalent.
Duplicate-key trick
The template gives the attacker one substitution point inside the name value. The outer {"name": " / "} is fixed. The attacker's payload:
x", "name": {"$ne": "x"}, "$comment": "bud-033
Renders to:
{"name": "x", "name": {"$ne": "x"}, "$comment": "bud-033"}
JSON.parse keeps the last value for a duplicate key (ECMA-404 leaves this implementation-defined; V8 and Node's JSON.parse keep the last), so the parsed object is:
{ name: { $ne: "x" }, $comment: "bud-033" }
$comment is a MongoDB meta operator that the server accepts and ignores, so it consumes the template's trailing "} without restricting the query. The filter that reaches MongoDB is name != "x", which matches every document.
Proof of Concept
Tested against Budibase 3.35.8 (master at f960e361) and MongoDB 6.
Step 1: Admin creates a MongoDB datasource and seeds three documents:
docker run -d --name mongo -p 27017:27017 mongo:6
docker exec mongo mongosh --quiet --eval '
db = db.getSiblingDB("testdb");
db.users.insertMany([
{name:"alice", email:"[email protected]", secret:"public-alice"},
{name:"bob", email:"[email protected]", secret:"PRIVATE-BOB"},
{name:"eve", email:"[email protected]", secret:"PRIVATE-EVE"}
]);'
Step 2: Alice, a builder, configures the datasource and writes a MongoDB query find-by-name whose json field is {"name": "{{name}}"}. She publishes the app and grants Bob (BASIC) a role on it.
Step 3: Bob, logged in as BASIC with a role on the published app, executes the query via the standard execute endpoint. POST /api/queries/:queryId is reachable by any app role with permission on…
- Record
GHSA-pmpg-2mxq-6xwr- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-rqxq-f5cc-3xp6
7.1
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource...
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
- Record
GHSA-rqxq-f5cc-3xp6- CVSS 4.0
- 7.1 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N - Weakness
- CWE-943
- Updated
- 2026-11-02
NVD
7.1
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
- Record
CVE-2026-73617- CVSS 4.0
- 7.1 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N - Weakness
- CWE-943
- Updated
- 2026-11-02
OSV
7.1
Budibase before 3.40.0 NoSQL Injection via MongoDB datasource
Budibase before 3.40.0 contains a NoSQL injection vulnerability in the MongoDB datasource integration where user-supplied parameters are enriched with handlebars using noEscaping: true and parsed without operator filtering. Attackers can inject MongoDB operators through query parameters to bypass per-user access controls, read arbitrary documents, execute JavaScript via $where operators, or modify collections through update and delete operations.
- Record
CVE-2026-73617- CVSS 4.0
- 7.1 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-943
- Updated
- 2026-11-02
OSVGHSA-pmpg-2mxq-6xwr
7.1
Budibase: NoSQL injection in MongoDB integration: collection dump, $where JS exec, cross-collection pivot, arbitrary update/delete
Summary
An end-user injection in Budibase's MongoDB datasource lets any BASIC app user bypass the builder's query-level access controls. Builders scope MongoDB reads per-user with bindings like {"email": "{{ currentUser.email }}"} so each app user only sees their own rows. Because the binding is handlebars-enriched into the query JSON with noEscaping: true and then JSON.parsed, Bob (a BASIC user) overrides the builder's filter with a MongoDB operator and reads every document the connection can touch. SQL datasources are parameterized through interpolateSQL(); the MongoDB path has no equivalent, so the scoping pattern Budibase's own docs show is unsafe.
Details
Enrichment
packages/server/src/sdk/workspace/queries/queries.ts:105-125 enriches every string field of the query with handlebars, then parses the enriched json field:
enrichedQuery[key] = processStringSync(fields[key], parameters, {
noEscaping: true,
noHelpers: true,
escapeNewlines: true,
})
// ...
enrichedQuery.json = JSON.parse(
enrichedQuery.json || enrichedQuery.customData || enrichedQuery.requestBody
)
noEscaping: true turns {{name}} into {{{name}}}, which Handlebars renders without HTML-escaping. Any " or } the attacker supplies lands verbatim in the enriched string. JSON.parse then produces a structured object whose top-level keys and operators came from the parameter value.
Execution
packages/server/src/integrations/mongodb.ts:499-512:
async read(query: MongoDBQuery) {
try {
await this.connect()
const db = this.client.db(this.config.db)
const collection = db.collection(query.extra.collection)
let json = this.createObjectIds(query.json)
switch (query.extra.actionType) {
case "find": {
if (json) {
return await collection.find(json).toArray()
}
createObjectIds walks the object and rewrites strings that look like ObjectId(...). It does not strip $-prefixed keys and does not reject operator-shaped values. The injected filter reaches collection.find unchanged.
For comparison, SQL datasources go through interpolateSQL at packages/server/src/threads/query.ts:145, which parameterizes bindings into driver-level bind variables. The MongoDB path has no equivalent.
Duplicate-key trick
The template gives the attacker one substitution point inside the name value. The outer {"name": " / "} is fixed. The attacker's payload:
x", "name": {"$ne": "x"}, "$comment": "bud-033
Renders to:
{"name": "x", "name": {"$ne": "x"}, "$comment": "bud-033"}
JSON.parse keeps the last value for a duplicate key (ECMA-404 leaves this implementation-defined; V8 and Node's JSON.parse keep the last), so the parsed object is:
{ name: { $ne: "x" }, $comment: "bud-033" }
$comment is a MongoDB meta operator that the server accepts and ignores, so it consumes the template's trailing "} without restricting the query. The filter that reaches MongoDB is name != "x", which matches every document.
Proof of Concept
Tested against Budibase 3.35.8 (master at f960e361) and MongoDB 6.
Step 1: Admin creates a MongoDB datasource and seeds three documents:
docker run -d --name mongo -p 27017:27017 mongo:6
docker exec mongo mongosh --quiet --eval '
db = db.getSiblingDB("testdb");
db.users.insertMany([
{name:"alice", email:"[email protected]", secret:"public-alice"},
{name:"bob", email:"[email protected]", secret:"PRIVATE-BOB"},
{name:"eve", email:"[email protected]", secret:"PRIVATE-EVE"}
]);'
Step 2: Alice, a builder, configures the datasource and writes a MongoDB query find-by-name whose json field is {"name": "{{name}}"}. She publishes the app and grants Bob (BASIC) a role on it.
Step 3: Bob, logged in as BASIC with a role on the published app, executes the query via the standard execute endpoint. POST /api/queries/:queryId is reachable by any app role with permission on…
- Record
GHSA-pmpg-2mxq-6xwr- CVSS 3.1
- 7.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@budibase/servernpm |
through 3.38.1 | None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-73617 is a high vulnerability (CVSS 7.1) in Budibase Server, published July 24, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. No source names a fixed version.
References
github.com/Budibase/budibase/security/advisories/GHSA-pmpg-2mxq-6xwr
vulncheck.com/advisories/budibase-before-nosql-injection-via-mongodb-datasource
github.com/Budibase/budibase/pull/18907
github.com/Budibase/budibase/commit/dd8c0654b35cd89ce3645f2355f4bf2ff9a5dd80
github.com/Budibase/budibase/releases/tag/3.39.9
github.com/advisories/GHSA-pmpg-2mxq-6xwr
Left out here: the rest of 2 source descriptions. The JSON record has them.