
Proof-of-concept exploit and advisory for CVE-2026-54356, a Budibase missing-authorization flaw that lets low-privilege users mint S3 pre-signed upload URLs with stored AWS credentials.
A low-privilege (BASIC role) authenticated user of a published Budibase workspace can call
POST /api/attachments/:datasourceId/url and obtain an S3 pre-signed upload URL signed with
the workspace datasource's server-side AWS credentials, for an attacker-controlled object
key (and, if the datasource has no fixed bucket, an attacker-controlled bucket too).
| CVE | CVE-2026-54356 |
| Advisory | GHSA-6x9p-4r67-5gjx |
| Package | @budibase/server |
| Type | CWE-862: Missing Authorization |
| Affected | < 3.41.3 |
| Fixed | 3.41.3 |
| Severity | High — CVSS 3.1 7.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N) |
| Privilege required | Authenticated BASIC app user |
packages/server/src/api/routes/static.ts:
.post(
"/api/attachments/:datasourceId/url",
recaptcha,
authorized(PermissionType.TABLE, PermissionLevel.WRITE), // too low, wrong resource
controller.getSignedUploadURL
)
packages/server/src/api/controllers/static/index.ts (getSignedUploadURL) loads the
datasource by :datasourceId, pulls its stored accessKeyId/secretAccessKey, and signs a
PutObject request for the attacker-supplied bucket/key:
const { bucket, key } = ctx.request.body || {}
const s3 = new S3({
credentials: {
accessKeyId: datasource?.config?.accessKeyId as string,
secretAccessKey: datasource?.config?.secretAccessKey as string,
},
})
signedUrl = await getSignedUrl(s3, new PutObjectCommand({ Bucket: bucket, Key: key }))
Minting a credential-backed signed URL is a privileged action, but the check only requires
generic table-write permission (which BASIC holds) and never verifies the caller is entitled to
use that specific datasource. Expected: 403. Actual: 200 with signedUrl/publicUrl.
PutObject pre-signed URLs signed with the org's stored AWS credentials.curl/PUT).See poc/:
poc/exploit.sh — curl PoC (login → mint signed URL → upload proof file).poc/poc.py — same flow in Python.python3 poc/poc.py \
--target http://localhost:10000 \
--app-id app_xxx --datasource-id datasource_xxx \
--email [email protected] --password 'Password123!' \
--bucket my-attachments --key poc/cve-2026-54356/proof.txt \
--upload
Upgrade to Budibase 3.41.3+. If you can't upgrade immediately, scope the S3 datasource's AWS
credentials to least-privilege (bucket/prefix-restricted IAM policy) and monitor for unexpected
PutObject activity.
Discovered and reported by @KovachVL.
For educational/defensive use and coordinated disclosure only. Only test systems you own or are explicitly authorized to test.