CVE-2026-73304: Budibase SSO OAuth2 Token Leakage Vulnerability
MODERATECVE-2026-73304 is a MODERATE (CVSS 4.9) sso oauth2 token leakage vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting Budibase libraries in the npm ecosystem. The issue involves sso oauth2 token leakage via user metadata endpoints to power-role users. Remediation is available by upgrading affected packages to version 3.39.25.
CVE-2026-73304 at a Glance
Security Impact
CVSS: 4.9
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N).
How to Fix CVE-2026-73304
To remediate this vulnerability, upgrade all affected Budibase dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install @budibase/server@3.39.25
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls @budibase/server
How to Check if You Are Affected
To determine whether your Node.js application is affected by CVE-2026-73304, inspect your project dependencies using npm:
npm ls @budibase/server
Analyze the terminal output to locate any version of Budibase in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.39.25), your application is affected.
Note: The npm ls @budibase/server command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In Budibase, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-73304 Affected Budibase Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
@budibase/server
|
npm |
< 3.39.25
|
3.39.25
|
References
Frequently Asked Questions
What is CVE-2026-73304?
Which Budibase versions are affected?
What version fixes CVE-2026-73304?
Is @budibase/server affected?
What is the CVSS score of CVE-2026-73304?
What CWE is associated with CVE-2026-73304?
How can I check npm dependencies for CVE-2026-73304?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-fcrw-f7gg-6g9f",
"modified" : "2026-08-12T18:57:12Z",
"published" : "2026-07-24T21:14:31Z",
"aliases" : [ "CVE-2026-73304" ],
"summary" : " Budibase: SSO OAuth2 Token Leakage via User Metadata Endpoints to Power-Role Users",
"details" : "## Summary\n\nThe `/api/users/metadata` and `/api/users/metadata/:id` endpoints in `@budibase/server` return full global user profiles to any user with POWER role or above. For SSO-authenticated users (OIDC, Google), the response includes `oauth2.accessToken` and `oauth2.refreshToken` fields, leaking identity provider credentials to other users who should not have access to them.\n\n## Details\n\nWhen a user authenticates via SSO (OIDC or Google), the OAuth2 tokens are stored in the global CouchDB user document at `packages/backend-core/src/auth/auth.ts:170-173`:\n\n```typescript\ndbUser.oauth2 = {\n ...dbUser.oauth2,\n ...details,\n}\nawait db.put(dbUser)\n```\n\nThe user metadata endpoints are protected by `PermissionType.USER, PermissionLevel.READ` (`packages/server/src/api/routes/user.ts:11`), which maps to the POWER permission set (`packages/backend-core/src/security/permissions.ts:99`).\n\n**Path 1 — List all users** (`GET /api/users/metadata`):\n1. `controller.fetchMetadata` → `sdk.users.fetchMetadata()` (`packages/server/src/sdk/users/utils.ts:78`)\n2. → `getGlobalUsers()` → `getRawGlobalUsers()` (`packages/server/src/utilities/global.ts:101-122`) — strips only `password` and `forceResetPassword`\n3. → `processUser()` (`packages/server/src/utilities/global.ts:15-76`) — strips only `password` and `roles`\n4. The `oauth2` field containing `accessToken` and `refreshToken` is **never removed**\n\n**Path 2 — Single user** (`GET /api/users/metadata/:id`):\n1. `controller.findMetadata` → `getFullUser()` (`packages/server/src/utilities/users.ts:6`)\n2. → `getGlobalUser()` → `getRawGlobalUser()` (`packages/server/src/utilities/global.ts:90-92`) — raw CouchDB fetch, **no field stripping at all**\n3. → `processUser()` — strips only `password` and `roles`\n4. Same result: `oauth2` tokens are returned\n\nThere is no output sanitization middleware on these routes that would strip sensitive fields before the response reaches the client.\n\n## PoC\n\n**Prerequisites:** A Budibase instance with at least one SSO-authenticated user (OIDC or Google) and a separate user with POWER role in an app.\n\n**Step 1 — As the POWER user, list all users:**\n```bash\ncurl -s -X GET 'http://localhost:10000/api/users/metadata' \\\n -H 'Cookie: budibase:auth=<power-user-jwt>' \\\n -H 'x-budibase-app-id: app_<appid>' | jq '.[].oauth2'\n```\n\n**Expected output:** `null` for all users (tokens should not be exposed)\n\n**Actual output:** For SSO users, the response includes:\n```json\n{\n \"accessToken\": \"ya29.a0ARrdaM...\",\n \"refreshToken\": \"1//0eXxXxXxXx...\"\n}\n```\n\n**Step 2 — Fetch a specific SSO user's profile:**\n```bash\ncurl -s -X GET 'http://localhost:10000/api/users/metadata/ro_ta_users_us_<sso-user-id>' \\\n -H 'Cookie: budibase:auth=<power-user-jwt>' \\\n -H 'x-budibase-app-id: app_<appid>' | jq '.oauth2'\n```\n\nThis also returns the full OAuth2 tokens.\n\n## Impact\n\n- A user with POWER role in any app can read **all SSO users' OAuth2 access tokens and refresh tokens** via the list endpoint, without needing to know individual user IDs.\n- Stolen access tokens can be used to access external identity provider resources (Google Workspace, Azure AD, Okta-protected services) as the victim user.\n- Refresh tokens allow indefinite token renewal, persisting access even after the original access token expires.\n- Additionally, `admin`, `builder`, `tenantId`, `ssoId`, and `userGroups` fields are leaked, revealing the full authorization topology of the instance.\n\n## Recommended Fix\n\nStrip sensitive SSO fields in `processUser()` at `packages/server/src/utilities/global.ts:15`:\n\n```typescript\nexport async function processUser(\n user: ContextUser,\n opts: { appId?: string; groups?: UserGroup[] } = {}\n) {\n if (!user || (!user.roles && !user.userGroups)) {\n return user\n }\n user = cloneDeep(user)\n delete user.password\n+ delete (user as any).oauth2\n+ delete (user as any).provider\n+ delete (user as any).providerType\n+ delete (user as any).thirdPartyProfile\n+ delete (user as any).profile\n+ delete (user as any).ssoId\n+ delete (user as any).forceResetPassword\n // ... rest of function\n```\n\nAdditionally, `getRawGlobalUsers()` at line 101 should also strip `oauth2` alongside its existing `password`/`forceResetPassword` stripping for defense in depth.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "@budibase/server"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "3.39.25"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/Budibase/budibase/security/advisories/GHSA-fcrw-f7gg-6g9f"
}, {
"type" : "WEB",
"url" : "https://github.com/Budibase/budibase/pull/19110"
}, {
"type" : "WEB",
"url" : "https://github.com/Budibase/budibase/commit/7b8ba11a2c8b233c35e7728dd752dba25ef919a4"
}, {
"type" : "WEB",
"url" : "https://github.com/Budibase/budibase/commit/80a31f6c3354620aa90e50af8a2c614333084621"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/Budibase/budibase"
}, {
"type" : "WEB",
"url" : "https://github.com/Budibase/budibase/releases/tag/3.39.25"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-200" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-24T21:14:31Z",
"nvd_published_at" : null
}
}