Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦 npm
Not in CISA KEV

GHSA-c8vc-7pv3-g98p — @budibase/server

GHSA-c8vc-7pv3-g98p is a CWE-639 vulnerability in @budibase/server. No vendor fix is recorded yet; mitigation options are listed below.

Budibase: Email Change IDOR via POST /api/v2/email allows full Account Takeover (accountId not validated against session)

Also known asCVE-2026-73303
Published
Jul 24, 2026
Updated
Aug 12, 2026
Affected
1 pkg
Patched
None yet
Exploits
None indexed
Exploitation data as of Sep 26, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • A successful exploit gives an attacker total control of the affected component, not partial access.
  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for GHSA-c8vc-7pv3-g98p.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs21th percentile — riskier than 21% of all scored CVEsHighest risk

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

1other npm packages depend on this — each one inherits the vulnerability until it's patched upstream
@budibase/servernpm
17Kdownloads / week

Description

Summary

POST /api/v2/email on the account portal (account.budibase.app) starts an email-change workflow using a client-supplied accountId that is not validated against the authenticated session. A logged-in attacker supplies a victim's accountId and an email address they control; the verification code is delivered to the attacker's address, and completing the workflow changes the victim's account email. The attacker then password-resets the victim's account through the controlled address and logs in — full account takeover with no victim interaction.

Vulnerability Details

The endpoint session-checks the currentEmail field (a mismatch returns 403), but it does not enforce body.accountId === session.accountId. The account-portal frontend only ever submits the logged-in user's own accountId, so in normal use the two always match — the server simply trusts the body value. An attacker who has a victim's accountId can point the workflow at the victim's account while passing their own currentEmail to clear the session check.

This is more powerful than a direct password reset: PUT /api/v2/auth/password {email} already exists and is gated only on knowing the victim's email, but the reset link is sent to the address on the account — the victim's inbox, which the attacker does not control. This IDOR moves the victim's email to an attacker-controlled inbox first, so the attacker receives the reset link and sets a password they know.

accountId obtainability. We checked every endpoint reachable from a non-admin free-tier account — GET /api/global/users (no UUID in any user record), GET /api/global/auditlogs/search (no accountId field), GET /api/global/users/invites (code + email + name only), GET /api/v2/tenant (one tenant-internal UUID, not a user accountId), the account-portal frontend (passes the session's own accountId only), and all unauthenticated endpoints — and the victim's accountId was not present in any of them. The attacker must obtain the UUID through some channel other than the normal API surface (support channel, screenshot, a leak, prior compromise, etc.).

Steps to Reproduce

Setup: Two account-portal accounts at https://account.budibase.app — Account A (attacker) and Account B (victim). From Account B's session, GET /api/auth/self returns account.accountId — this is the value the attacker needs.

  1. Start the email-change workflow pointed at the victim's accountId, newEmail = attacker-controlled.
POST /api/v2/email HTTP/1.1
Host: account.budibase.app
Content-Type: application/json
Cookie: budibase:auth=<ACCOUNT_A_JWT>

{"currentEmail":"<ACCOUNT_A_EMAIL>","newEmail":"[email protected]","accountId":"<VICTIM_ACCOUNT_ID>"}

Response: 201 Created, sets budibase:change_email:correlationkey (HttpOnly), :instancekey, :status, :newemail cookies. The workflow started against the victim's accountId even though the caller is Account A.

  1. Complete the change with the code from the attacker-controlled inbox (or read directly from the correlationkey cookie set in step 1).
POST /api/v2/email/verification HTTP/1.1
Host: account.budibase.app
Content-Type: application/json
Cookie: budibase:auth=<ACCOUNT_A_JWT>; budibase:change_email:correlationkey=<CODE>; budibase:change_email:instancekey=<KEY>

{"verificationCode":"<code>","processInstanceKey":"<key>"}

Response: 200 OK. The victim's account email is now [email protected].

  1. Confirm the change hit the victim, not the caller (false-positive control).
  • Account A (caller) still logs in with its own original email — 200, unchanged.
  • Account B's (victim) original email is now rejected — 403, locked out.
  • [email protected] now logs into the victim's account — 200.
  1. Take over the account.
PUT /api/v2/auth/password HTTP/1.1
Host: account.budibase.app
Content-Type: application/json

{"email":"[email protected]"}

Response: 202 Accepted, reset link delivered to the attacker's own inbox. Complete the reset with PUT /api/v2/auth/password/verification, then log in as the victim with the attacker-chosen password. GET /api/auth/self afterward returns the victim's real accountId and tenantId — full account takeover, confirmed via a genuinely separate account/tenant (not a same-account self-test).

Impact

An authenticated account-portal user who obtains a victim's accountId (out-of-band — it is not exposed anywhere in the normal cross-user API surface we could find) can take over that victim's account: rewrite the login email to an attacker address, set a new password, and access the victim's tenants, apps, and stored datasource credentials (REST/SQL/S3 auth). The victim is locked out of their own account. Every step from the initial IDOR write to full login-as-victim is deterministic and 100% reliable once the accountId is known — no additional vulnerability or guessing is required, since the chain uses nothing but the platform's own stock password-reset flow.

Remediation

Validate that the body's accountId equals the authenticated session's accountId before starting or completing the email-change workflow (the same check already applied to currentEmail). Do not trust a client-supplied accountId to select the workflow target.

Affected Packages

1 total
EcosystemPackageVulnerable rangeFix
📦npm@budibase/serverall versionsNo fix

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for @budibase/server, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Remediation status

    No patched version of @budibase/server has shipped for GHSA-c8vc-7pv3-g98p yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.

  3. Mitigate without a patch

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Frequently Asked Questions

## Summary `POST /api/v2/email` on the account portal (`account.budibase.app`) starts an email-change workflow using a client-supplied `accountId` that is **not validated against the authenticated session**. A logged-in attacker supplies a victim's `accountId` and an email address they control; the verification code is delivered to the attacker's address, and completing the workflow changes the **victim's** account email. The attacker then password-resets the victim's account through the controlled address and logs in — full account takeover with no victim interaction. ## Vulnerability Detai
O3 Security · Impact-Aware SCA

Is GHSA-c8vc-7pv3-g98p in your dependencies?

Find it across npm, including transitive dependencies.