A AegiFlow
HIGHCVSS 8.5

GHSA-v42f-v8xc-j435

Budibase: SSRF via DNS rebinding in the REST datasource integration

Published
2026-07-24
Modified
2026-07-24
Sources
github-advisory

Summary

### Summary Budibase's central outbound-fetch guard (`fetchWithBlacklist`) prevents SSRF/DNS-rebinding by resolving the target hostname, checking every resolved IP against the blacklist, and **pinning** the connection to the validated IP. The pin is implemented as a Node `http(s).Agent` (`makePinnedAgent`). The fix for CVE-2026-54353 relies on this pin to stop DNS rebinding. The REST datasource integration (`@budibase/server`) calls `fetchWithBlacklist` but performs the actual request with **undici**'s `fetch`. undici does not support the Node `agent` option — it is silently ignored — and instead uses its own `dispatcher`, which re-resolves the hostname's DNS at connection time. As a result, **the validated/pinned IP is never used on the REST datasource path**, and the DNS-rebinding protection that CVE-2026-54353 added is silently defeated for the single most-used outbound path in Budibase. An authenticated user who can configure/run a REST datasource (e.g. a builder/tenant) can use a rebinding hostname (public IP during validation, internal IP at connect) to make the server issue arbitrary, full-response HTTP requests to internal-only services — cloud metadata (IAM credential theft), the internal CouchDB/Redis/MinIO, and other internal endpoints — reading and, because REST datasources allow arbitrary method/body, writing or destroying internal data. ### Details **The guard pins the validated IP via a Node agent** — `packages/backend-core/src/utils/outboundFetch.ts`: - `resolveSafePinnedIp(url)` resolves the hostname and checks every address against `isBlacklisted`, returning a single `pinnedIp` (lines ~39–53). - `makePinnedAgent(url, ip)` builds a **Node** `http.Agent`/`https.Agent` whose `lookup` always returns `pinnedIp`, so a node-fetch connection can only reach the validated IP (lines ~55–68). - `fetchWithBlacklist` passes that agent into the request: `fetchFn(nextUrl, { ...nextRequest, agent: makePinnedAgent(nextUrl, pinnedIp) })` (lines ~186–192). Each redirect hop is re-validated and re-pinned in the loop. **The REST integration overrides the transport with undici, which ignores `agent`** — `packages/server/src/integrations/rest.ts`: - `fetch` is imported from **`undici`** (top-of-file import block, ~line 30). - The request is made by overriding `fetchFn` (lines ~767–793): ```ts const setDispatcher = (requestInput, requestUrl) => ({ ...requestInput, dispatcher: getDispatcher({ rejectUnauthorized, url: requestUrl }), }) ... response = await coreUtils.fetchWithBlacklist(url, input, { fetchFn: async (requestUrl, requestInput) => fetch(requestUrl, setDispatcher(requestInput, requestUrl)), // undici.fetch }) ``` The options object reaching `undici.fetch` is `{ ...nextRequest, agent: , dispatcher: }`. **undici uses `dispatcher` and ignores `agent`.** **The dispatcher does no IP pinning** — `packages/backend-core/src/utils/fetch.ts`: - `getDispatcher` → `createDispatcher` → (no proxy env) → `createDirectAgent` = `new Agent({ connect: { rejectUnauthorized } })` (lines ~109–114, ~161–172, ~183). This is a plain undici `Agent` with **no `connect.lookup` / no pin**, so undici resolves the hostname's DNS itself at connect time. **Net effect (TOCTOU / DNS rebinding):** `fetchWithBlacklist` validates the hostname → safe public IP and builds a pinned Node agent; the REST path then connects via undici, which re-resolves the same hostname independently. With a rebinding domain (TTL 0: public IP during validation, `127.0.0.1` / `169.254.169.254` / internal IP at connect), the request lands on an internal service — exactly the gap CVE-2026-54353's pin was meant to close. **Scope of impact / why it's REST-specific:** `rest.ts` is the only caller that overrides `fetchFn` with undici. All other outbound sinks (automation `outgoingWebhook`/`n8n`/`make`/`zapier`/`discord`/`slack`, and AI-extract's `processUrlFile`) use the default node-fetch-based `fetchWit

Affected packages

EcosystemPackageAffected versionsFixed versions
npm@budibase/server

Remediation: No patched version is listed by GitHub.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.