# Budibase: SSRF via OAuth2 Config Validation — Missing fetchWithBlacklist Protection

Budibase OAuth2 token fetch used raw fetch() instead of fetchWithBlacklist, letting a BUILDER SSRF internal CouchDB and cloud metadata and leak client secrets.

- Payout: Research
- Severity: high
- Program: Budibase
- Found by: axel-corsiez
- Disclosed: 2026-06-12
- CVE: CVE-2026-48146
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-g6qx-g4pr-92v7
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-g6qx-g4pr-92v7
- Tags: area:web domain:web impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix technique:source-review vuln:ssrf

**Target:** OAuth2 token validation endpoint (/api/oauth2/validate) and REST integration fetch
**Root cause:** The OAuth2 token fetch in sdk/workspace/oauth2/utils.ts:59 calls raw fetch(config.url) without the fetchWithBlacklist() wrapper used for all other outbound calls; the REST integration also checks the blacklist only on the initial URL and follows redirects unchecked.
**Steps:**
1. Identify that fetchToken uses raw `fetch(config.url, fetchConfig)` while other outbound calls use `fetchWithBlacklist`.
2. As a BUILDER user, POST to `/api/oauth2/validate` with `{"url":"http://127.0.0.1:9999/ssrf","clientId":"test","clientSecret":"test"}` pointing at an attacker listener.
3. Observe the listener receives a POST with `Authorization: Basic` containing the client_id/client_secret.
4. Point url at `http://127.0.0.1:5984/_all_dbs` to confirm internal CouchDB reachability via `{"valid":false,"message":"Unauthorized"}`.
5. Point url at `http://169.254.169.254/latest/meta-data/` in cloud deployments to reach metadata.
6. For the REST integration, supply an external URL that 302-redirects to `169.254.169.254` since only the initial URL is blacklist-checked.
**How found:** Code review noticing a consistency gap: fetchWithBlacklist exists and is used in every other outbound HTTP call (automation steps, plugin downloads, object store) but not in the OAuth2 token fetch; the REST integration's single pre-redirect blacklist check was similarly spotted.
**Exploitation:** A builder-role user submits an OAuth2 config whose token URL targets internal services or cloud metadata; the server issues the request server-side, leaking Basic-auth credentials to attacker URLs and returning internal responses/error differences for recon. The REST integration variant uses an attacker-controlled redirect to reach metadata despite the initial blacklist check.
**Escalation:** Chaining the SSRF with cloud metadata access yields IAM credentials; error-difference probing enables internal port scanning.
**Insight:** When a codebase has a central safe-fetch wrapper, grep for raw `fetch(`/`undici.fetch(` call sites and diff them against wrapper usage — the one outlier is the bug; also check whether the wrapper re-validates redirects (`redirect: "manual"`) versus following them.

## Proof of concept (copied exactly from the original report)

**curl POST to oauth2/validate with internal URL**

```
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"}'
```

