Sploitus

Exploit for CVE-2026-54356

githubexploit Β· 2026-08-14

Exploit Code

README87 lines
## https://sploitus.com/exploit?id=587C8DB9-01FF-56C6-B7D9-02DCEDE7C8B5
# CVE-2026-54356 β€” Budibase: authenticated arbitrary S3 signed upload URL issuance

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](https://github.com/Budibase/budibase/security/advisories/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 |

## Root cause

`packages/server/src/api/routes/static.ts`:

```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`:

```ts
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`.

## Impact

- Attacker gets valid `PutObject` pre-signed URLs signed with the org's stored AWS credentials.
- Can write/overwrite arbitrary object keys in the datasource bucket, and β€” when no bucket is
  pinned in the datasource config β€” potentially any bucket those credentials can reach.
- The signed URL works off-platform (plain `curl`/`PUT`).

## PoC

See [`poc/`](poc/):
- [`poc/exploit.sh`](poc/exploit.sh) β€” curl PoC (login β†’ mint signed URL β†’ upload proof file).
- [`poc/poc.py`](poc/poc.py) β€” same flow in Python.

```bash
python3 poc/poc.py \
  --target http://localhost:10000 \
  --app-id app_xxx --datasource-id datasource_xxx \
  --email basic@example.com --password 'Password123!' \
  --bucket my-attachments --key poc/cve-2026-54356/proof.txt \
  --upload
```

## Remediation

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.

## Credit

Discovered and reported by [@KovachVL](https://github.com/KovachVL).

## Disclaimer

For educational/defensive use and coordinated disclosure only. Only test systems you own or are
explicitly authorized to test.