Home/ Blog/ Security news/ Article
Blog · Security news

A single Budibase app builder can read your server's secrets and take over every workspace

CVE-2026-54352 lets a Budibase workspace builder read the server's secret file via a crafted PWA zip and take over every workspace. Patch self-hosted to 3.39.9.

Sealed shipping container with one inner panel open and a thread leading out

The same Budibase feature has now leaked the server's secrets twice in three months. In March, a path-traversal bug in the progressive web app (PWA) icon uploader let a logged-in builder read files outside the upload folder, and on Budibase Cloud it exposed credentials across every tenant. That hole was closed. CVE-2026-54352, published June 22, reopens it through a different door: a symbolic link hidden inside the uploaded archive. The patched release is 3.39.9, and if you run Budibase yourself, this is today's work.

The flaw is rated 9.6. A user with the builder role, a routine permission in most internal-tools deployments, can read any file the server process can open. That includes /data/.env with the JWT_SECRET and INTERNAL_API_KEY, the database and object-store passwords, and, on the default container image, system files such as /etc/shadow. Holding the signing secret, that same builder can mint a token for the global administrator and move across every workspace on the instance.

What the bug actually does

Budibase lets a builder upload a zip to turn an app into an installable progressive web app. The server unpacks the archive, reads an icons.json manifest, checks that each icon path stays inside the extraction folder, then streams the matching files into its object store so it can serve them back as the app's icons.

The check looks only at the path string. It resolves the icon source, confirms the text starts with the extraction folder, and confirms a file exists there. What it never asks is whether that path is a symbolic link. The unpacker keeps a symlink's absolute target intact, so an entry can sit at a perfectly legal location inside the folder, pass every string test, and still point at /data/.env. When the server opens the file to stream it, the operating system follows the link and returns the target's bytes. Those bytes come straight back out of the asset-serving endpoint.

Jan Kahmen of turingpoint reported the chain and documented it in the GitHub advisory. There is no working exploit to reproduce here, and you do not need one: the point is that a single crafted upload turns a low-trust role into full secret disclosure. The record is mirrored on OSV as CVE-2026-54352, classified as both a path-handling and a link-resolution flaw.

Cloud is fine this time. Self-hosters are not.

This is the mirror image of the March bug. CVE-2026-30240 hit Budibase Cloud hardest: that advisory reports it read process environment data on production and exposed 19 secrets affecting all 2,519 tenants. CVE-2026-54352 lands the other way. Budibase Cloud runs on a sandboxed filesystem and is not affected. The damage falls on self-hosted instances, and worst on the default Docker image, which runs the server as root. As root, the read is not limited to the app's own files; it covers the whole disk.

So the question of who must act flipped. In March, the cloud tenants were the victims and self-hosters had time. This time the cloud is covered and the self-hosters are the ones exposed. If you adopted Budibase for an internal tool and forgot it was even running, it is back on the list.

Two arbitrary-file-reads in the same uploader in three months is not bad luck. Both grow from one assumption: that checking a path string is the same as checking the file you are about to open. It is not. The March fix sanitized the string. This bug shows that a sanitized string can still resolve anywhere on disk once a symlink sits in the path. The durable fix for this class is to refuse symlinks at the door, with a link-aware stat or a no-follow open, and to treat any validation that runs before the open as advice rather than a guarantee. We have seen the same lesson when a single overlooked secret was enough to take over an entire cluster: the control that looked sufficient was checking the wrong thing.

Patch to 3.39.9, then rotate your secrets

Update self-hosted Budibase to 3.39.9 now. That closes the file read. It does not undo a read that already happened, and that gap matters more here than usual, because the prize is JWT_SECRET, and a stolen signing secret keeps working after the patch lands. If you cannot rule out that a builder account abused this, rotate everything in /data/.env: the JWT secret, the internal API key, and your database, object-store, and cache passwords. Upgrading alone leaves a forged-token path open, the same way a credential leak keeps paying out until the leaked credentials are changed.

Two more steps shrink the blast radius for next time. Run the container as a non-root user, so a file read is capped at what the app account can open instead of the entire host. And audit who holds the builder or creator role. This is a post-login bug, so the people who can reach the upload are the people you already trusted to build apps, which in many shops is a wider group than it should be.

What to watch in your logs

If you keep request logs, a PWA package upload shows up as a write to the PWA processing route, followed by icon fetches under the app's PWA path. A builder account uploading PWA packages it never used before, or asset responses that are larger than an icon and are not actually images, are worth a second look. None of that replaces patching. It answers the after-the-fact question of whether anyone already tried.

Budibase moves fast and ships fixes fast, and the turnaround here is real. But the same feature failing the same way twice is a signal worth heeding: if you run an internal-tools platform that lets users upload archives, the upload path needs a hard look at symlink handling, not just string validation. Patch to 3.39.9, rotate if you might have been read, and get that container off root.

Frequently asked questions

What is CVE-2026-54352 in Budibase?

CVE-2026-54352 is a critical arbitrary file read in self-hosted Budibase, scored CVSS 9.6. A user with the builder role uploads a progressive web app zip containing a symbolic link, which the server follows to read files such as /data/.env. It is patched in version 3.39.9.

Is Budibase Cloud affected by this bug?

No. Budibase Cloud runs on a sandboxed filesystem and is not affected by CVE-2026-54352. The exposure falls on self-hosted instances, and is worst on the default Docker image because it runs the server process as root, which lets the read reach the entire disk.

Which Budibase versions are vulnerable and what is the fix?

Self-hosted Budibase versions before 3.39.9 are vulnerable. The fix is release 3.39.9, which rejects the symlinked icon path. Upgrade as soon as you can, because the flaw lets a builder reach the server's signing key and forge a global administrator.

What can an attacker actually read?

Any file the server process can open. That includes the /data/.env file with the JWT signing secret, the internal API key, and the database and object-store passwords. On the default container image, which runs as root, it also reaches system files like /etc/shadow.

I already patched. Am I safe?

Patching closes the read but does not undo one that already happened. The flaw exposes JWT_SECRET, and a stolen signing key keeps working after the upgrade. If you cannot rule out abuse by a builder account, rotate the JWT secret, the internal API key, and your database, cache, and object-store passwords.

Who can exploit this vulnerability?

A logged-in user with the builder role, the permission needed to create or edit apps. It is not a pre-authentication bug, so the attacker must already have builder access. In many internal-tools deployments that role is granted widely, which makes the privilege jump from builder to full instance owner the real risk.

Ready to meet the Guardians?

Deploys fast - agentless for monitoring and cloud, a lightweight agent for deep endpoint security. Just Suriq, standing watch.