GitHub Advisoryadvisory · npm
GHSA-8qv3-p479-cj62 Budibase has nonymous NoSQL operator injection via published-app query templates
CRITICAL
Official page ↗
- Aliases
- CVE-2026-54350
- Ecosystem
- npm
- Packages
- @budibase/server
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
- Weaknesses
- CWE-89, CWE-943
- Reviewed
- 2026-06-23
Affected packages
• npm @budibase/server: < 3.39.12 → fixed in 3.39.12
Description
Summary
`enrichContext` at `packages/server/src/sdk/workspace/queries/queries.ts:121-138` substitutes parameter values into the raw JSON body of a query, then `JSON.parse`s the result. The validator `validateQueryInputs` at `packages/server/src/api/controllers/query/index.ts:61-71` rejects only Handlebars markers (`{{`, `}}`) in user input and does not escape JSON metacharacters (`"`, `\`, `}`). A parameter value containing a closing quote and additional keys lifts attacker-controlled fields into the parsed filter object.
For Mongo `find`, the parsed filter passes directly to `collection.find()` (`packages/server/src/integrations/mongodb.ts:506-510`). Duplicate-key JSON parsing overrides the builder's `{name: "..."}` with `{name: {$exists: true}}` and returns every document. The same primitive against an `updateMany` query (`mongodb.ts:577-585`) widens the filter scope to the full collection while the builder-controlled `$set` body runs against every matched document.
The `authorized` middleware at `packages/server/src/middleware/authorized.ts:141-148` short-circuits when the query's role is `PUBLIC`. CSRF is not enforced on this path. `POST /api/v2/queries/:queryId` (`packages/server/src/api/routes/query.ts:63`) accepts the call with no session, only an `x-budibase-app-id` header that is public from the published-app URL.
Result: an unauthenticated visitor of any published Budibase app reads every document of the backing MongoDB, CouchDB, Elasticsearch, DynamoDB-PartiQL, or REST-with-JSON-body collection and, where the builder has published a PUBLIC write query, modifies every document of that collection with one HTTP request.
Affected
`Budibase/budibase` server, `@budibase/server` package, ` HTTP/1.1
Host:
x-budibase-app-id:
Content-Type: application/json
{"parameters":{"name":"x\",\"name\":{\"$exists\":true},\"$comment\":\"audit"}}
```
```json
{"data":[
{"_id":"...","name":"alice","secret":"alice-secret-flag"},
{"_id":"...","name":"bob","secret":"bob-secret-flag"},
{"_id":"...","name":"admin","role":"admin","secret":"ADMIN-SUPER-SECRET-FLAG"}
]}
```
2. Builder publishes a second query `TouchUser` (verb `update`, action `updateMany`, body `{ "filter": { "name": "{{ name }}" }, "update": { "$set": { "touched": true } } }`, role `PUBLIC`). Anonymous client sends the same inject pattern.
```http
POST /api/v2/queries/ HTTP/1.1
Host:
x-budibase-app-id:
Content-Type: application/json
{"parameters":{"name":"x\",\"name\":{\"$exists\":true},\"$comment\":\"esc"}}
```
```json
{"data":[{"acknowledged":true,"matchedCount":3,"modifiedCount":3,"upsertedId":null,"upsertedCount":0}]}
```
Live-verified: against Budibase v3.39.0 on 2026-05-20, anonymous read returned every document including `ADMIN-SUPER-SECRET-FLAG`; anonymous `updateMany` reported `matchedCount: 3, modifiedCount: 3` against a 3-document collection where the builder's filter intended `name = "x"`.
Impact
• Anonymous read of every document in any backing MongoDB, CouchDB, Elasticsearch, DynamoDB-PartiQL, or REST-with-JSON-body collection reachable through a `PUBLIC` query, including columns the published query was not designed to return (`password_hash`, `secret`, `api_token`, `mfa_secret`).
• Anonymous modification of every document of that collection where the builder has published a `PUBLIC` `update`, `delete`, or `aggregate` query, beyond the builder's intended single-document scope.
• One HTTP request, no session, no CSRF, no user interaction.
Credit
Jan Kahmen, turingpoint ([email protected]).
Related
Alias · CVE (1)
- CVE-2026-54350 Budibase is an open-source low-code platform. vulnerability