GHSA-5FPJ-28RV-84R7
Vulnerability from github – Published: 2026-08-14 19:18 – Updated: 2026-08-14 19:18Summary
Budibase automation steps (outgoing webhook, Zapier, n8n, Slack, Discord, Make.com) make server-side HTTP requests to user-provided URLs using node-fetch directly, completely bypassing the IP blacklist protection that exists in the REST API integration. Additionally, the REST API blacklist itself defaults to empty when BLACKLIST_IPS is not configured.
Vulnerable Code
Automation Steps (No Blacklist)
All automation steps use fetch() directly without any IP validation:
packages/server/src/automations/steps/outgoingWebhook.ts line 69:
const response = await fetch(url, request) // No blacklist check
packages/server/src/automations/steps/zapier.ts line 34:
response = await fetch(url, {method: "post", ...}) // No blacklist check
packages/server/src/automations/steps/n8n.ts line 53:
response = await fetch(url, request) // No blacklist check
packages/server/src/automations/steps/slack.ts line 20:
response = await fetch(url, {method: "post", ...}) // No blacklist check
packages/server/src/automations/steps/discord.ts line 29:
response = await fetch(url, {method: "post", ...}) // No blacklist check
REST API Integration (Empty Default Blacklist)
packages/server/src/integrations/rest.ts line 684:
if (await blacklist.isBlacklisted(url)) {
throw new Error("Cannot connect to URL.")
}
But BLACKLIST_IPS env var defaults to undefined, so the blacklist is empty:
packages/backend-core/src/blacklist/blacklist.ts lines 39-45:
if (blackListArray?.length === 0) {
return false // Always passes when no IPs configured
}
Impact
- Automation steps: ANY user can create automations with webhook/Zapier/n8n/Slack/Discord steps pointing to internal IPs. These completely bypass the blacklist module
- REST API: Even when BLACKLIST_IPS is configured, it only blocks listed IPs. Default deployments have no protection.
- Cloud metadata:
http://169.254.169.254/latest/meta-data/accessible via any automation step - Internal services: Access databases, admin panels, Kubernetes API on private IPs
Remediation
- Apply blacklist checks to ALL outbound HTTP requests, including automation steps
- Add hardcoded default private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16)
- Use a centralized HTTP client wrapper instead of direct
fetch()calls - SSRF protection should be on by default, not opt-in via environment variable
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@budibase/server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.41.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-35219"
],
"database_specific": {
"cwe_ids": [
"CWE-918"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-14T19:18:47Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\nBudibase automation steps (outgoing webhook, Zapier, n8n, Slack, Discord, Make.com) make server-side HTTP requests to user-provided URLs using `node-fetch` directly, completely bypassing the IP blacklist protection that exists in the REST API integration. Additionally, the REST API blacklist itself defaults to empty when `BLACKLIST_IPS` is not configured.\n\n## Vulnerable Code\n\n### Automation Steps (No Blacklist)\n\nAll automation steps use `fetch()` directly without any IP validation:\n\n**`packages/server/src/automations/steps/outgoingWebhook.ts` line 69:**\n```typescript\nconst response = await fetch(url, request) // No blacklist check\n```\n\n**`packages/server/src/automations/steps/zapier.ts` line 34:**\n```typescript\nresponse = await fetch(url, {method: \"post\", ...}) // No blacklist check\n```\n\n**`packages/server/src/automations/steps/n8n.ts` line 53:**\n```typescript\nresponse = await fetch(url, request) // No blacklist check\n```\n\n**`packages/server/src/automations/steps/slack.ts` line 20:**\n```typescript\nresponse = await fetch(url, {method: \"post\", ...}) // No blacklist check\n```\n\n**`packages/server/src/automations/steps/discord.ts` line 29:**\n```typescript\nresponse = await fetch(url, {method: \"post\", ...}) // No blacklist check\n```\n\n### REST API Integration (Empty Default Blacklist)\n\n**`packages/server/src/integrations/rest.ts` line 684:**\n```typescript\nif (await blacklist.isBlacklisted(url)) {\n throw new Error(\"Cannot connect to URL.\")\n}\n```\n\nBut `BLACKLIST_IPS` env var defaults to undefined, so the blacklist is empty:\n\n**`packages/backend-core/src/blacklist/blacklist.ts` lines 39-45:**\n```typescript\nif (blackListArray?.length === 0) {\n return false // Always passes when no IPs configured\n}\n```\n\n## Impact\n\n- **Automation steps**: ANY user can create automations with webhook/Zapier/n8n/Slack/Discord steps pointing to internal IPs. These completely bypass the blacklist module\n- **REST API**: Even when BLACKLIST_IPS is configured, it only blocks listed IPs. Default deployments have no protection.\n- **Cloud metadata**: `http://169.254.169.254/latest/meta-data/` accessible via any automation step\n- **Internal services**: Access databases, admin panels, Kubernetes API on private IPs\n\n## Remediation\n\n1. Apply blacklist checks to ALL outbound HTTP requests, including automation steps\n2. Add hardcoded default private IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16)\n3. Use a centralized HTTP client wrapper instead of direct `fetch()` calls\n4. SSRF protection should be on by default, not opt-in via environment variable",
"id": "GHSA-5fpj-28rv-84r7",
"modified": "2026-08-14T19:18:47Z",
"published": "2026-08-14T19:18:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Budibase/budibase/security/advisories/GHSA-5fpj-28rv-84r7"
},
{
"type": "PACKAGE",
"url": "https://github.com/Budibase/budibase"
},
{
"type": "WEB",
"url": "https://github.com/Budibase/budibase/releases/tag/3.41.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Budibase: SSRF in Automation Steps - Webhook, Zapier, N8N, Slack, Discord Bypass IP Blacklist"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.