CVE-2026-48150
Description
Budibase is an open-source low-code platform. Prior to 3.39.0, /api/public/v1/roles/assign is guarded by the builderOrAdmin middleware, which passes any user who is a builder for the app id in the x-budibase-app-id header. That check admits both global builders and workspace-scoped builders (builder.apps set but builder.global unset). The controller then spreads the request body into the SDK call, and the SDK grants builder.global=true or admin.global=true on whichever user ids the caller supplies. Bob, a workspace-scoped builder with an API key, promotes himself or any other user to global admin with one POST. The whole flow is tenant-wide privilege escalation from an app-level role, available to anyone with an Enterprise license that unlocks the EXPANDED_PUBLIC_API feature. This vulnerability is fixed in 3.39.0.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Budibase before 3.39.0 lets workspace-scoped builders escalate to global admin via the /api/public/v1/roles/assign endpoint.
Vulnerability
Prior to version 3.39.0, the Budibase low-code platform exposes the /api/public/v1/roles/assign endpoint, which is guarded by the builderOrAdmin middleware. This middleware passes any user who is a builder for the app ID supplied in the x-budibase-app-id header, including workspace-scoped builders (with builder.apps set but builder.global unset). The controller spreads the request body directly into an SDK call that unconditionally sets builder.global=true or admin.global=true on the supplied user IDs, without verifying that the caller holds those privileges. The vulnerable code path is available only when the EXPANDED_PUBLIC_API feature is enabled via an Enterprise license [1].
Exploitation
An attacker must have a valid API key for a workspace-scoped builder account and an Enterprise license (to unlock the feature). They also need to know or guess the target user IDs. They send a single POST request to /api/public/v1/roles/assign with a JSON body containing { "userIds": [""], "admin": true } (or "builder": true). No additional authentication checks or user interaction are required; the builderOrAdmin middleware passes because the attacker is a builder for the app ID in the header. The SDK then overwrites the target user's admin.global or builder.global fields to true, granting global admin or builder privileges tenant-wide [1].
Impact
A workspace-scoped builder can escalate their own privileges or those of any other user to global admin or global builder across the entire tenant. This represents a privilege escalation from an app-level role to the highest tenant-level role, leading to complete compromise of confidentiality, integrity, and availability of the Budibase instance. The escalation also strips any existing app-specific scope from the target user [1].
Mitigation
The vulnerability is fixed in Budibase version 3.39.0. All users running earlier versions should upgrade immediately. There is no workaround if the EXPANDED_PUBLIC_API feature is required; disabling the feature (by downgrading the license) removes the attack surface. The CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog [1].
AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
1feab9955aeb5Bump version to 3.39.0
1 file changed · +1 −1
lerna.json+1 −1 modified@@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.38.5", + "version": "3.39.0", "npmClient": "yarn", "concurrency": 20, "command": {
Vulnerability mechanics
Root cause
"Missing privilege check in the SDK allows workspace-scoped builders to grant global builder or global admin privileges via mass-assignment of request body properties."
Attack vector
An attacker who is a workspace-scoped builder (with an API key) sends a POST to `/api/public/v1/roles/assign` with a JSON body containing `userIds` (targeting themselves or another user) and either `"builder":true` or `"admin":true`. The request is scoped to the attacker's app via the `x-budibase-app-id` header, which passes the `builderOrAdmin` middleware because the attacker is a builder for that app. The controller spreads the body into the SDK, which unconditionally sets `builder.global=true` or `admin.global=true` on the targeted user ids. This results in tenant-wide privilege escalation from an app-level role to global admin [ref_id=1]. The attack is available to anyone with an Enterprise license that unlocks the `EXPANDED_PUBLIC_API` feature [ref_id=1].
Affected code
The controller at `packages/server/src/api/controllers/public/roles.ts:13-17` spreads the request body's `builder` and `admin` keys directly into the SDK call without filtering. The SDK at `packages/pro/src/sdk/publicApi/roles.ts:17-47` unconditionally sets `user.builder = { global: true }` or `user.admin = { global: true }` for any supplied user ids, with no check that the caller holds the privilege they are granting. The `builderOrAdmin` middleware (`packages/backend-core/src/middleware/builderOrAdmin.ts:6-20`) passes workspace-scoped builders (those with `builder.apps` set but `builder.global` unset) because `isBuilder(user, workspaceId)` returns true for any user whose `builder.apps` array contains the workspace id [ref_id=1].
What the fix does
The patch enforces the caller's privilege in the SDK at `packages/pro/src/sdk/publicApi/roles.ts`, matching the grant they want to make. Before setting `user.builder = { global: true }`, the fix checks whether the caller has `builder.global` or `admin.global`; before setting `user.admin = { global: true }`, it checks whether the caller has `admin.global`. If the caller lacks the required privilege, the SDK throws a 403 error. This closes the vulnerability by ensuring that a workspace-scoped builder cannot grant global builder or global admin privileges [ref_id=1].
Preconditions
- authAttacker must be a workspace-scoped builder (builder.apps set, builder.global unset) with an API key
- configTenant must have an Enterprise license that unlocks the EXPANDED_PUBLIC_API feature
- inputAttacker must know the app ID of the workspace they are a builder for
- networkNetwork access to the Budibase server API endpoint /api/public/v1/roles/assign
Reproduction
Step 1: The admin creates two users — Alice (workspace-scoped builder on an app, `builder.global` unset) and a victim (BASIC user). Step 2: Alice calls `GET /api/global/self/api_key` to obtain her API key. Step 3: Alice sends a POST to `/api/public/v1/roles/assign` with the victim's user id and `"builder":true`, scoped to her app via `x-budibase-app-id`. Step 4: Alice sends a second POST with her own user id and `"admin":true`, promoting herself to global admin [ref_id=1].
Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
1News mentions
0No linked articles in our index yet.