Vulnerability Analysis

CVE-2026-41428: Budibase Authentication Bypass via Unanchored Regex — What It Is & How to Fix It

Executive Summary

CVE-2026-41428 is a critical authentication bypass vulnerability (CVSS 9.1) in Budibase, the popular open-source low-code platform, publicly disclosed on April 24, 2026. The flaw allows unauthenticated attackers to reach any protected API endpoint by exploiting an unanchored regular expression in Budibase's authentication middleware — bypassing access controls entirely by embedding a known public-route path inside a URL query parameter. Organizations running self-hosted or cloud Budibase deployments on versions prior to 3.35.4 should patch immediately.


1. What Is This Vulnerability?

Budibase's backend authentication middleware maintains a list of "public" endpoints — routes that do not require a valid session (e.g., /api/system/status, /api/global/auth/login). To decide whether to enforce authentication on an incoming request, the middleware checks the request URL against a set of regular expressions derived from these public route patterns.

The critical flaw: the regular expressions are unanchored. Instead of matching only at the start of the path (^/api/system/status), they match anywhere in the string. Because the Koa web framework exposes ctx.request.url as the full URL including the query string, an attacker can manufacture a URL like:

POST /api/global/users/search?x=/api/system/status

The middleware evaluates the full string /api/global/users/search?x=/api/system/status against the regex /api/system/status/ — the pattern matches inside the query string, so the middleware classifies the entire request as a public, unauthenticated endpoint. The real handler (/api/global/users/search) then executes with no session check.

The affected file is packages/backend-core/src/middleware/authenticated.ts (and equivalent compiled output) in all Budibase releases before 3.35.4.

Attack Vector

The attack is entirely network-based and requires no prior credentials, no user interaction, and no special tooling — a standard curl command is sufficient. The attacker:

  1. Identifies any protected Budibase API endpoint (admin routes, user data, app configuration).
  2. Appends a query parameter whose value is a known public path string.
  3. Sends the request without an Authorization header or valid session cookie.
  4. Receives a successful response as if fully authenticated.

Example exploit request:

POST /api/global/users/search?x=/api/system/status HTTP/1.1
Host: budibase.example.com
Content-Type: application/json

{"query": {}}

A vulnerable instance responds with a full list of user accounts. No credentials required.

Real-World Impact

Budibase is widely used for internal tooling, admin dashboards, and data-entry applications — environments that commonly store PII, credentials, API keys, and business-critical data inside their backing databases. Because Budibase self-hosted instances are frequently deployed on internal networks with the assumption that authentication provides the security boundary, exploitation could lead to:

  • Full database exfiltration — listing all users, apps, and table data.
  • Account takeover — modifying user records or resetting admin credentials.
  • Secrets exposure — reading stored API keys and environment variables accessible through app configuration endpoints.
  • Lateral movement — using harvested credentials to pivot into other internal systems.

At the time of disclosure, no public mass-exploitation campaigns had been confirmed, but the simplicity of the attack makes opportunistic exploitation highly likely against internet-exposed instances.


2. Who Is Affected?

Component Affected Versions Fixed Version
@budibase/backend-core < 3.35.4 3.35.4+
@budibase/server < 3.35.4 3.35.4+
Budibase Cloud (SaaS) Patched by vendor N/A
Self-hosted Docker All images built before 3.35.4 Pull updated image
Self-hosted Kubernetes (Helm) All charts deploying < 3.35.4 Update chart values

Who should act urgently:

  • Any team running a self-hosted Budibase instance accessible from the internet or an internal network with untrusted users.
  • Teams using Budibase to manage sensitive data, admin workflows, or user management portals.
  • CI/CD pipelines or automation systems with Budibase API keys embedded — those keys may be extractable via this bypass.

Budibase Cloud (budibase.app) was patched by the Budibase team at the time of disclosure and requires no action from SaaS users.


3. How to Detect It (Testing)

Manual Testing Steps

Step 1 — Identify the Budibase version:

curl -s https://your-budibase-host/api/system/status | jq .version

If the version is below 3.35.4, the instance is vulnerable.

Step 2 — Probe a protected endpoint without authentication:

Choose a protected endpoint that would normally require a valid session. The global user-search route is a reliable test target:

curl -s -X POST "https://your-budibase-host/api/global/users/search?x=/api/system/status" \
  -H "Content-Type: application/json" \
  -d '{"query": {}}' \
  | jq .

Step 3 — Interpret the response:

  • Vulnerable: The server returns a 200 OK with a JSON object containing user data (email addresses, roles, etc.).
  • Patched: The server returns 401 Unauthorized or 403 Forbidden.

⚠️ Only test against instances you own or have explicit written permission to test. Unauthorized probing is illegal.

Automated Scanning

Tool: Nuclei

A community Nuclei template for CVE-2026-41428 can be run as follows:

nuclei -u https://your-budibase-host \
       -t cves/2026/CVE-2026-41428.yaml \
       -severity critical

Check the ProjectDiscovery nuclei-templates repository for the latest template.

Tool: Burp Suite Active Scan

  1. Authenticate normally to your Budibase instance and record a session with Burp's proxy.
  2. Use Burp's Active Scanner on the /api/global/users/search endpoint.
  3. Add a custom scan check: append ?x=/api/system/status to the URL and remove the Authorization header.
  4. Flag any 200 response as a confirmed vulnerability.

Tool: OWASP ZAP

Enable the Forced Browse add-on and configure a custom payload list:

/api/global/users/search?x=/api/system/status
/api/global/users?x=/api/system/status
/api/global/self?x=/api/system/status

Run an unauthenticated scan; any 200 response indicates the bypass is active.

Code Review Checklist

If you maintain a fork or customized deployment of Budibase:

  • Search for publicRoutes or PUBLICENDPOINTS in authenticated.ts — verify all regex patterns begin with ^ and end with $ or (?:/|$).
  • Confirm that ctx.request.url is not used for authentication path matching; use ctx.request.path instead (path does not include the query string).
  • Verify middleware unit tests include adversarial URLs with query-string injection payloads.
  • Check for similar patterns in any custom middleware added by your engineering team.

4. How to Fix It (Mitigation)

Step-by-Step Remediation

Option A — Upgrade (Recommended)

  1. Check your current version:

    docker exec budibase-apps cat /app/package.json | grep '"version"'
    
  2. Pull the patched Docker image:

    docker pull budibase/budibase:3.35.4
    # or use the latest tag if you track latest:
    docker pull budibase/budibase:latest
    
  3. Stop and recreate the container (Docker Compose):

    cd /path/to/your/budibase-compose/
    docker-compose pull
    docker-compose up -d
    
  4. Verify the updated version:

    curl -s https://your-budibase-host/api/system/status | jq .version
    # Should return "3.35.4" or higher
    
  5. Monitor logs for any anomalous unauthenticated requests that may indicate the instance was probed before patching.

Option B — Temporary Network Mitigation (if immediate upgrade is not possible)

Until you can upgrade, reduce exposure by:

  • Placing Budibase behind a VPN or IP allowlist at the network/firewall level so only trusted IP ranges can reach the application.
  • Disabling public-internet access to the Budibase instance entirely if it is only used internally.
  • Enabling Web Application Firewall (WAF) rules that reject requests where a path segment appears in the query string for API routes.

Note: Network mitigations are a stopgap only. Upgrade to 3.35.4 as soon as possible.

Code Fix Example

The root cause in authenticated.ts (simplified):

Before (vulnerable):

// Unanchored — matches anywhere in the full URL including query string
const PUBLIC_ROUTES = [
  /\/api\/system\/status/,
  /\/api\/global\/auth\/login/,
  // ...
]

function isPublicRoute(ctx: Koa.Context): boolean {
  return PUBLIC_ROUTES.some(pattern => pattern.test(ctx.request.url))
  //                                                 ^^^^^^^^^^^^^^^^
  //   ctx.request.url = "/api/global/users/search?x=/api/system/status"
  //   The pattern /\/api\/system\/status/ matches inside the query string!
}

After (patched):

// Use ctx.request.path (path only, no query string) with anchored regexes
const PUBLIC_ROUTES = [
  /^\/api\/system\/status(?:\/|$)/,
  /^\/api\/global\/auth\/login(?:\/|$)/,
  // ...
]

function isPublicRoute(ctx: Koa.Context): boolean {
  return PUBLIC_ROUTES.some(pattern => pattern.test(ctx.request.path))
  //                                                 ^^^^^^^^^^^^^^^^
  //   ctx.request.path = "/api/global/users/search"
  //   No match — authentication is enforced correctly.
}

Two changes were required: (1) switch from ctx.request.url to ctx.request.path, and (2) anchor all patterns with ^ so they cannot match mid-string.

Configuration Hardening

Beyond patching, harden your Budibase deployment:

  • Restrict API access at the reverse proxy level. In Nginx, deny direct external access to /api/* routes and only allow them through your front-end or VPN:

    location /api/ {
      allow 10.0.0.0/8;
      deny all;
      proxy_pass http://budibase-backend;
    }
    
  • Enable Budibase audit logging. Turn on the audit log feature in your Budibase admin panel so that all API access (authenticated or not) is recorded.

  • Rotate all secrets post-incident. If you believe your instance may have been accessed before patching, rotate API keys, database credentials, and any secrets stored in Budibase environment configuration.


5. How to Test the Fix (Validation)

Regression Test Scenarios

  • Scenario A: Send the exploit payload to a fully patched 3.35.4 instance → expect 401 Unauthorized.
  • Scenario B: Authenticate with a valid user session and hit the same endpoint normally → expect 200 OK with correct data (functionality not broken by the patch).
  • Scenario C: Send a request to a genuinely public endpoint (/api/system/status) without authentication → expect 200 OK (public routes still work correctly).

Security Test Cases

Test Case 1 — Verify the bypass no longer works

  • Precondition: Budibase upgraded to 3.35.4 or later.
  • Steps:
    1. Send POST /api/global/users/search?x=/api/system/status with no Authorization header.
    2. Record the HTTP response status code.
  • Expected Result: 401 Unauthorized. Any 2xx status is a test failure.

Test Case 2 — Verify authenticated requests still work

  • Precondition: Valid admin session token obtained via /api/global/auth/login.
  • Steps:
    1. Send POST /api/global/users/search with a valid Authorization: Bearer <token> header.
  • Expected Result: 200 OK with user list.

Test Case 3 — Verify public endpoints remain accessible

  • Precondition: No session cookie or auth header.
  • Steps:
    1. Send GET /api/system/status.
  • Expected Result: 200 OK with system status JSON.

Automated Tests

Add this Jest/Supertest integration test to your CI pipeline:

import request from 'supertest';
import app from '../src/app'; // your Budibase Koa app instance

describe('CVE-2026-41428 regression', () => {
  it('should reject unauthenticated access to protected endpoints via query injection', async () => {
    const res = await request(app)
      .post('/api/global/users/search?x=/api/system/status')
      .set('Content-Type', 'application/json')
      .send({ query: {} });

    expect(res.status).toBe(401);
  });

  it('should still allow access to genuinely public endpoints', async () => {
    const res = await request(app).get('/api/system/status');
    expect(res.status).toBe(200);
  });
});

6. Prevention & Hardening

Best Practices

  • Always anchor route-matching regexes. Any regex used for security decisions (authentication gates, authorization checks, rate limiting) must use ^ and $ anchors. Unanchored patterns in security-sensitive code are a recurring vulnerability class.

  • Match on path, not url. When processing HTTP requests in middleware, use the path component exclusively for routing and access-control decisions. The query string is attacker-controlled and should never influence authentication logic.

  • Adopt allowlist middleware patterns. Instead of checking if a URL matches a public route (and otherwise assuming protection), consider explicitly requiring authentication for all routes and opting out for public ones using decorators or a strict allowlist checked against the exact path.

  • Run automated security tests in CI. Include regression tests for known bypass techniques (query string injection, path traversal, method override) in your CI/CD pipeline so regressions are caught before deployment.

  • Conduct regular dependency audits. Tools like npm audit, Snyk, or Dependabot will surface newly published CVEs in your dependency tree. Set up automated alerts so your team learns of vulnerabilities the day they are disclosed, not weeks later.

Monitoring & Detection

To detect active exploitation attempts against your Budibase instance:

  1. Nginx/Reverse Proxy Log Analysis — Alert on any request to a protected API path (/api/global/, /api/apps/, /api/admin/) that also contains another API path in the query string:

    grep -E '(GET|POST) /api/[^?]+\?[^"]*=/api/' /var/log/nginx/access.log
    
  2. Budibase Audit Log — Review for any admin-level actions (user listing, config changes) correlated with low or zero-authentication session records. Unexpected admin activity from unfamiliar IPs without a corresponding login event is a strong indicator.

  3. SIEM Rules — Add a detection rule: HTTP request where uri_path is a protected route AND uri_query contains /api/ substring. Flag for immediate investigation.

  4. Rate Limiting — Implement rate limiting on all /api/ routes at the reverse proxy layer. Brute-force enumeration of endpoints via this bypass becomes detectable when hundreds of requests arrive from a single IP.


References

Latest from the blog

See all →