Vulnerability Database

363,159

Total vulnerabilities in the database

Budibase: SSO OAuth2 Token Leakage via User Metadata Endpoints to Power-Role Users — @budibase / server

Exposure of Sensitive Information to an Unauthorized Actor

Summary

The /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.

Details

When 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:

dbUser.oauth2 = { ...dbUser.oauth2, ...details, } await db.put(dbUser)

The 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).

Path 1 — List all users (GET /api/users/metadata):

  1. controller.fetchMetadatasdk.users.fetchMetadata() (packages/server/src/sdk/users/utils.ts:78)
  2. getGlobalUsers()getRawGlobalUsers() (packages/server/src/utilities/global.ts:101-122) — strips only password and forceResetPassword
  3. processUser() (packages/server/src/utilities/global.ts:15-76) — strips only password and roles
  4. The oauth2 field containing accessToken and refreshToken is never removed

Path 2 — Single user (GET /api/users/metadata/:id):

  1. controller.findMetadatagetFullUser() (packages/server/src/utilities/users.ts:6)
  2. getGlobalUser()getRawGlobalUser() (packages/server/src/utilities/global.ts:90-92) — raw CouchDB fetch, no field stripping at all
  3. processUser() — strips only password and roles
  4. Same result: oauth2 tokens are returned

There is no output sanitization middleware on these routes that would strip sensitive fields before the response reaches the client.

PoC

Prerequisites: A Budibase instance with at least one SSO-authenticated user (OIDC or Google) and a separate user with POWER role in an app.

Step 1 — As the POWER user, list all users:

curl -s -X GET 'http://localhost:10000/api/users/metadata' \ -H 'Cookie: budibase:auth=<power-user-jwt>' \ -H 'x-budibase-app-id: app_<appid>' | jq '.[].oauth2'

Expected output: null for all users (tokens should not be exposed)

Actual output: For SSO users, the response includes:

{ "accessToken": "ya29.a0ARrdaM...", "refreshToken": "1//0eXxXxXxXx..." }

Step 2 — Fetch a specific SSO user's profile:

curl -s -X GET 'http://localhost:10000/api/users/metadata/ro_ta_users_us_<sso-user-id>' \ -H 'Cookie: budibase:auth=<power-user-jwt>' \ -H 'x-budibase-app-id: app_<appid>' | jq '.oauth2'

This also returns the full OAuth2 tokens.

Impact

  • 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.
  • Stolen access tokens can be used to access external identity provider resources (Google Workspace, Azure AD, Okta-protected services) as the victim user.
  • Refresh tokens allow indefinite token renewal, persisting access even after the original access token expires.
  • Additionally, admin, builder, tenantId, ssoId, and userGroups fields are leaked, revealing the full authorization topology of the instance.

Strip sensitive SSO fields in processUser() at packages/server/src/utilities/global.ts:15:

export async function processUser( user: ContextUser, opts: { appId?: string; groups?: UserGroup[] } = {} ) { if (!user || (!user.roles && !user.userGroups)) { return user } user = cloneDeep(user) delete user.password + delete (user as any).oauth2 + delete (user as any).provider + delete (user as any).providerType + delete (user as any).thirdPartyProfile + delete (user as any).profile + delete (user as any).ssoId + delete (user as any).forceResetPassword // ... rest of function

Additionally, getRawGlobalUsers() at line 101 should also strip oauth2 alongside its existing password/forceResetPassword stripping for defense in depth.

  • Published: Jul 24, 2026
  • Updated: Jul 25, 2026
  • GHSA: GHSA-fcrw-f7gg-6g9f
  • Severity: Medium
  • Exploit:
  • CISA KEV:

CVSS v3:

  • Severity: Low
  • Score: 4.9
  • AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N

CWEs:

Frequently Asked Questions

A security vulnerability is a weakness in software, hardware, or configuration that can be exploited to compromise confidentiality, integrity, or availability. Many vulnerabilities are tracked as CVEs (Common Vulnerabilities and Exposures), which provide a standardized identifier so teams can coordinate patching, mitigation, and risk assessment across tools and vendors.

CVSS (Common Vulnerability Scoring System) estimates technical severity, but it doesn't automatically equal business risk. Prioritize using context like internet exposure, affected asset criticality, known exploitation (proof-of-concept or in-the-wild), and whether compensating controls exist. A "Medium" CVSS on an exposed, production system can be more urgent than a "Critical" on an isolated, non-production host.

A vulnerability is the underlying weakness. An exploit is the method or code used to take advantage of it. A zero-day is a vulnerability that is unknown to the vendor or has no publicly available fix when attackers begin using it. In practice, risk increases sharply when exploitation becomes reliable or widespread.

Recurring findings usually come from incomplete Asset Discovery, inconsistent patch management, inherited images, and configuration drift. In modern environments, you also need to watch the software supply chain: dependencies, containers, build pipelines, and third-party services can reintroduce the same weakness even after you patch a single host. Unknown or unmanaged assets (often called Shadow IT) are a common reason the same issues resurface.

Use a simple, repeatable triage model: focus first on externally exposed assets, high-value systems (identity, VPN, email, production), vulnerabilities with known exploits, and issues that enable remote code execution or privilege escalation. Then enforce patch SLAs and track progress using consistent metrics so remediation is steady, not reactive.

SynScan combines attack surface monitoring and continuous security auditing to keep your inventory current, flag high-impact vulnerabilities early, and help you turn raw findings into a practical remediation plan.