Loading...
Skip to main content

CVE-2026-54350

CRITICAL

Budibase has nonymous NoSQL operator injection via published-app query templates

Published June 23, 2026Updated August 12, 2026Source: osv

Summary

## 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, `<= 3.39.0` (HEAD `feab995`, released 2026-05-20). Reachable on any deployment where a workspace builder has set the role of a non-SQL query (MongoDB, CouchDB, Elasticsearch, DynamoDB-PartiQL, or REST with `bodyType=json`) to `PUBLIC` and published the app. This is the canonical low-code public-form use case. SQL datasources (Postgres, MySQL, MSSQL, Oracle, MariaDB) route through `interpolateSQL` and are not affected. ## Root cause `packages/server/src/sdk/workspace/queries/queries.ts:121-138`: `processStringSync(fields[key], parameters, {noEscaping: true, noHelpers: true})` writes the raw parameter value into the JSON-body string with no JSON-string escape; the followup `JSON.parse(enrichedQuery.json || enrichedQuery.customData || enrichedQuery.requestBody)` lifts the substituted text into the integration filter object. `packages/server/src/api/controllers/query/index.ts:61-71`: `validateQueryInputs` only rejects values where `findHBSBlocks(value).length !== 0` (Handlebars markers) and ignores JSON metacharacters. `packages/server/src/integrations/mongodb.ts:506-510`: `collection.find(json)` receives the user-controlled filter object directly with no key prefix or operator allow-list. `packages/server/src/integrations/mongodb.ts:577-585`: `collection.updateMany(json.filter, json.update, json.options)` accepts the templated filter without verifying that the substituted filter still matches the builder's intent. `packages/server/src/middleware/authorized.ts:141-148`: `if (resourceRoles.includes(roles.BUILTIN_ROLE_IDS.PUBLIC)) return next()` skips both authentication and CSRF. `packages/server/src/integrations/queries/sql.ts:29-122`: `interpolateSQL` rewrites every `{{ binding }}` to a positional bind placeholder (`$N` or `?`). The SQL leg is bind-parameterised; the JSON leg is not. ## Reproduction `budibase/budibase:latest` (`v3.39.0`) Docker single-container, default config. Builder logs in once, creates a MongoDB datasource, creates a query `GetUserByName` with body `{ "name": "{{ name }}" }`, sets the query role to `PUBLIC`, and publishes the app. 1. Anonymous client sends the inject payload to the read query. ```http POST /api/v2/queries/<read-queryId> HTTP/1.1 Host: <budibase-host> x-budibase-app-id: <published-appId> 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/<updateMany-queryId> HTTP/1.1 Host: <budibase-host> x-budibase-app-id: <published-appId> 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](https://turingpoint.de) (jan@turingpoint.de).

Remediation

Upgrade to the fixed version using your package manager.

npm
Update @budibase/server to 3.39.12 or later
npm install @budibase/server@3.39.12

After upgrading, run your dependency scanner again to confirm the vulnerability is resolved.

Affected Packages (1)

PackageEcosystemAffectedFixed In
@budibase/server
npm
All versions3.39.12

Vulnerability Classification

Common Weakness Enumeration (CWE) identifiers for this vulnerability type.

CVSS Score Breakdown

What the CVSS (Common Vulnerability Scoring System) 10.0 score means for each attack dimension.

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
None

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N

Frequently Asked Questions

What is CVE-2026-54350?
Budibase has nonymous NoSQL operator injection via published-app query templates This vulnerability has been assigned a severity rating of CRITICAL (CVSS score: 10.0/10).
How do I check if my project is affected by CVE-2026-54350?
CVE-2026-54350 affects @budibase/server. Use GeekWala's free vulnerability scanner to check your dependencies against CVE-2026-54350 and 200,000+ other known vulnerabilities.

Severity & Exploitability

CVSS Score
10.0

Exploitation is straightforward and causes maximum impact. Patch immediately.

Also Known As

GHSA-8qv3-p479-cj62

Related CVEs

  • CVE-2026-48150
    CRITICAL

    Budibase: Workspace-scoped builder escalates to global admin via /api/public/v1/roles/assign

  • CVE-2026-35216
    CRITICAL

    Budibase: Unauthenticated Remote Code Execution via Webhook Trigger and Bash Automation Step

  • CVE-2026-73302
    CRITICAL

    Budibase: OIDC SSO account takeover: incoming identity linked by email without checking email_verified

  • CVE-2026-35214
    HIGH

    Budibase: Path traversal in plugin file upload enables arbitrary directory deletion and file write

  • CVE-2026-50137
    HIGH

    Budibase: POST /api/attachments/:datasourceId/url is unauthenticated and lets anonymous callers mint S3 PUT pre-signed URLs using stored datasource IAM credentials

  • CVE-2026-45717
    HIGH

    Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL

  • CVE-2026-25044
    HIGH

    Budibase: Command Injection in Bash Automation Step

  • CVE-2026-73305
    HIGH

    Budibase: Privilege escalation via public role assignment API missing app-level authorization

Check if you're affected

Scan your dependencies to see if this vulnerability affects your projects.

Scan Your Dependencies