Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 274/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 13:09 UTC Customize Public modeDiscuss ChangeIntel on Discord

Budibase: Path traversal in plugin file upload enables arbitrary directory deletion and file write

Collected exploitation and prediction evidence

Risk source coverage

CISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.

No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.

cve-program · CVE-2026-35214

Published

Budibase is an open-source low-code platform. Prior to version 3.33.4, the plugin file upload endpoint (POST /api/plugin/upload) passes the user-supplied filename directly to createTempFolder() without sanitizing path traversal sequences. An attacker with Global Builder privileges can craft a multipart upload with a filename containing ../ to delete arbitrary directories via rmSync and write arbitrary files via tarball extraction to any filesystem path the Node.js process can access. This issue has been patched in version 3.33.4.

Source published
3 Apr 2026 15:43:12 UTC
Source modified
3 Apr 2026 16:04:36 UTC
Observed here
23 Oct 2026 15:48:27 UTC
Source terms
CVE Program Terms of Use

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · 8.7 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H

euvd · EUVD-2026-18793

Published

Budibase is an open-source low-code platform. Prior to version 3.33.4, the plugin file upload endpoint (POST /api/plugin/upload) passes the user-supplied filename directly to createTempFolder() without sanitizing path traversal sequences. An attacker with Global Builder privileges can craft a multipart upload with a filename containing ../ to delete arbitrary directories via rmSync and write arbitrary files via tarball extraction to any filesystem path the Node.js process can access. This issue has been patched in version 3.33.4.

EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.

Original publisher date fields

datePublished: Apr 3, 2026, 3:43:12 PM

dateUpdated: Apr 3, 2026, 4:04:36 PM

Source published
Apr 3, 2026, 3:43:12 PM (timezone not stated)
Source modified
Apr 3, 2026, 4:04:36 PM (timezone not stated)
Observed here
11 Nov 2026 09:30:27 UTC
Source terms
ENISA EUVD · source terms and attribution apply

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.

EUVD CVSS 3.1 · 8.7 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H

nvd · CVE-2026-35214

Published

Budibase is an open-source low-code platform. Prior to version 3.33.4, the plugin file upload endpoint (POST /api/plugin/upload) passes the user-supplied filename directly to createTempFolder() without sanitizing path traversal sequences. An attacker with Global Builder privileges can craft a multipart upload with a filename containing ../ to delete arbitrary directories via rmSync and write arbitrary files via tarball extraction to any filesystem path the Node.js process can access. This issue has been patched in version 3.33.4.

NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.

Source analysis status: Analyzed

Weakness classifications: CWE-22

Original publisher date fields

published: 2026-04-03T16:16:41.607

lastModified: 2026-10-06T22:10:00.247

1 source CPE criteria · context only
  • cpe:2.3:a:budibase:budibase:*:*:*:*:*:*:*:*

The original JSON retains the logical configuration operators, exclusions and version bounds.

Source published
3 Apr 2026 16:16:41 UTC
Source modified
6 Oct 2026 22:10:00 UTC
Observed here
25 Oct 2026 08:17:41 UTC
Source terms
NIST NVD usage terms; underlying source attribution retained

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · [email protected] · Secondary · 8.7 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H

osv · GHSA-2wfh-rcwf-wh23

Published

## Summary The plugin file upload endpoint (`POST /api/plugin/upload`) passes the user-supplied filename directly to `createTempFolder()` without sanitizing path traversal sequences. An attacker with Global Builder privileges can craft a multipart upload with a filename containing `../` to delete arbitrary directories via `rmSync` and write arbitrary files via tarball extraction to any filesystem path the Node.js process can access. ## Severity - **Attack Vector:** Network — exploitable via the plugin upload HTTP API - **Attack Complexity:** Low — no special conditions; a single crafted multipart request suffices - **Privileges Required:** High — requires Global Builder role (`GLOBAL_BUILDER` permission) - **User Interaction:** None - **Scope:** Changed — the plugin upload feature is scoped to a temp directory, but the traversal escapes to the host filesystem - **Confidentiality Impact:** None — the vulnerability enables deletion and writing, not reading - **Integrity Impact:** High — attacker can delete arbitrary directories and write arbitrary files via tarball extraction - **Availability Impact:** High — recursive deletion of application or system directories causes denial of service ### Severity Rationale Despite the real filesystem impact, severity is bounded by the requirement for Global Builder privileges (PR:H), which is the highest non-admin role in Budibase. In self-hosted deployments the Global Builder may already have server access, further reducing practical impact. In cloud/multi-tenant deployments the impact is more significant as it could affect the host infrastructure. ## Affected Component - `packages/server/src/api/controllers/plugin/file.ts` — `fileUpload()` (line 15) - `packages/server/src/utilities/fileSystem/filesystem.ts` — `createTempFolder()` (lines 78-91) ## Description ### Unsanitized filename flows into filesystem operations In `packages/server/src/api/controllers/plugin/file.ts`, the uploaded file's name is used directly after stripping the `.tar.gz` suffix: ```typescript // packages/server/src/api/controllers/plugin/file.ts:8-19 export async function fileUpload(file: KoaFile) { if (!file.name || !file.path) { throw new Error("File is not valid - cannot upload.") } if (!file.name.endsWith(".tar.gz")) { throw new Error("Plugin must be compressed into a gzipped tarball.") } const path = createTempFolder(file.name.split(".tar.gz")[0]) await extractTarball(file.path, path) return await getPluginMetadata(path) } ``` The `file.name` originates from the `Content-Disposition` header's `filename` field in the multipart upload, parsed by formidable (via koa-body 4.2.0). Formidable does not sanitize path traversal sequences from filenames. The `createTempFolder` function in `packages/server/src/utilities/fileSystem/filesystem.ts` uses `path.join()` which resolves `../` sequences, then performs destructive filesystem operations: ```typescript // packages/server/src/utilities/fileSystem/filesystem.ts:78-91 export const createTempFolder = (item: string) => { const path = join(budibaseTempDir(), item) try { // remove old tmp directories automatically - don't combine if (fs.existsSync(path)) { fs.rmSync(path, { recursive: true, force: true }) } fs.mkdirSync(path) } catch (err: any) { throw new Error(`Path cannot be created: ${err.message}`) } return path } ``` The `budibaseTempDir()` returns `/tmp/.budibase` (from `packages/backend-core/src/objectStore/utils.ts:33`). With a filename like `../../etc/target.tar.gz`, `path.join("/tmp/.budibase", "../../etc/target")` resolves to `/etc/target`. ### Inconsistent defenses confirm the gap The codebase is aware of the risk in similar paths: 1. **Safe path in `utils.ts`**: The `downloadUnzipTarball` function (for NPM/GitHub/URL plugin sources) generates a random name server-side: ```typescript // packages/server/src/api/controllers/plugin/index.ts:68 const name = "PLUGIN_" + Math.floor(100000 + Math.random() * 900000) ``` This is safe because `name` never contains user input. 2. **Safe path in `objectStore.ts`**: Other uses of `budibaseTempDir()` use UUID-generated names: ```typescript // packages/backend-core/src/objectStore/objectStore.ts:546 const outputPath = join(budibaseTempDir(), v4()) ``` 3. **Sanitization exists but is not applied**: The codebase has `sanitizeKey()` in `objectStore.ts` for sanitizing object store paths, but no equivalent is applied to `createTempFolder`'s input. The file upload path is the only caller of `createTempFolder` that passes unsanitized user input. ### Execution chain 1. Authenticated Global Builder sends `POST /api/plugin/upload` with a multipart file whose `Content-Disposition` filename contains path traversal (e.g., `../../etc/target.tar.gz`) 2. koa-body/formidable parses the upload, setting `file.name` to the raw filename from the header 3. `controller.upload` → `sdk.plugins.processUploaded()` → `fileUpload(file)` 4. `.endsWith(".tar.gz")` check passes (the suffix is present) 5. `.split(".tar.gz")[0]` extracts `../../etc/target` 6. `createTempFolder("../../etc/target")` is called 7. `path.join("/tmp/.budibase", "../../etc/target")` resolves to `/etc/target` 8. `fs.rmSync("/etc/target", { recursive: true, force: true })` — **deletes the target directory recursively** 9. `fs.mkdirSync("/etc/target")` — **creates a directory at the traversed path** 10. `extractTarball(file.path, "/etc/target")` — **extracts attacker-controlled tarball contents to the traversed path** ## Proof of Concept ```bash # Create a minimal tarball with a test file mkdir -p /tmp/plugin-poc && echo "pwned" > /tmp/plugin-poc/test.txt tar czf /tmp/poc-plugin.tar.gz -C /tmp/plugin-poc . # Upload with a traversal filename targeting /tmp/pwned (non-destructive demo) curl -X POST 'http://localhost:10000/api/plugin/upload' \ -H 'Cookie: <global_builder_session_cookie>' \ -F "file=@/tmp/poc-plugin.tar.gz;filename=../../tmp/pwned.tar.gz" # Result: server executes: # rm -rf /tmp/pwned (if exists) # mkdir /tmp/pwned # tar xzf <upload> -C /tmp/pwned # Verify: ls /tmp/pwned/test.txt ``` ## Impact - **Arbitrary directory deletion**: `rmSync` with `{ recursive: true, force: true }` deletes any directory the Node.js process can access, including application data directories - **Arbitrary file write**: Tarball extraction writes attacker-controlled files to any writable path, potentially overwriting application code, configuration, or system files - **Denial of service**: Deleting critical directories (e.g., the application's data directory, node_modules, or system directories) crashes the application - **Potential code execution**: In containerized deployments (common for Budibase) where Node.js runs as root, an attacker could overwrite startup scripts or application code to achieve remote code execution on subsequent restarts ## Recommended Remediation ### Option 1: Sanitize at `createTempFolder` (preferred — protects all callers) ```typescript import { join, resolve } from "path" export const createTempFolder = (item: string) => { const tempDir = budibaseTempDir() const resolved = resolve(tempDir, item) // Ensure the resolved path is within the temp directory if (!resolved.startsWith(tempDir + "/") && resolved !== tempDir) { throw new Error("Invalid path: directory traversal detected") } try { if (fs.existsSync(resolved)) { fs.rmSync(resolved, { recursive: true, force: true }) } fs.mkdirSync(resolved) } catch (err: any) { throw new Error(`Path cannot be created: ${err.message}`) } return resolved } ``` ### Option 2: Sanitize at the upload handler (defense-in-depth) Strip path components from the filename before use: ```typescript import path from "path" export async function fileUpload(file: KoaFile) { if (!file.name || !file.path) { throw new Error("File is not valid - cannot upload.") } if (!file.name.endsWith(".tar.gz")) { throw new Error("Plugin must be compressed into a gzipped tarball.") } // Strip directory components from the filename const safeName = path.basename(file.name).split(".tar.gz")[0] const dir = createTempFolder(safeName) await extractTarball(file.path, dir) return await getPluginMetadata(dir) } ``` Both options should ideally be applied together for defense-in-depth. ## Credit This vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).

Source published
4 Apr 2026 06:04:19 UTC
Source modified
4 Apr 2026 06:26:31 UTC
Observed here
24 Oct 2026 13:17:17 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H

Publisher rating · HIGH

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 11 Nov 13:09 UTC · 274 of 275 readable · 273 fully read · documentation 469/469 current