Budibase: S3 presigned URL endpoint authorization regression in v3.39.4 allows BASIC…
Key facts
- Attack vector
- —
- Privileges required
- —
- User interaction
- —
- Attack complexity
- —
- Impact type
- Security bypass
- Confidentiality · integrity · availability
- —
- Fix status
- No fix listed
No CVSS vector from any source. Fix status from GitHub. Impact type from CWE-863.
Summary
## Impact In Budibase v3.39.4, a regression in the authorization level for the S3 attachment upload endpoint allows any BASIC app user to obtain S3 PutObject presigned URLs. The endpoint uses TABLE/WRITE permission level instead of the intended BUILDER level defined in v3.39.3. Additionally, the controller does not pin the target bucket to the datasource's configured bucket, allowing writes to any S3 bucket the stored IAM credentials can access. ## Reproduction 1. As a BASIC app user, discover or obtain a valid S3 datasource ID within the app 2. Send a POST request: ``` POST /api/attachments/<datasourceId>/url Content-Type: application/json x-budibase-app-id: <appId> {"bucket": "target-bucket", "key": "malicious-file.html"} ``` 3. The response contains a valid S3 PutObject presigned URL 4. Use the presigned URL to upload arbitrary content to any writable S3 bucket in the IAM credential scope ## Root Cause The `/api/attachments/:datasourceId/url` route was changed from `authorized(BUILDER)` in v3.39.3 to `authorized(PermissionType.TABLE, PermissionLevel.WRITE)` in v3.39.4. BASIC users have TABLE/WRITE permissions by default, so they can call this endpoint. The controller at `packages/server/src/api/controllers/static/index.ts:614-632` accepts the `bucket` parameter directly from the request body and passes it to `getSignedUrl` without validating against the datasource's configured bucket. ## Evidence The test suite at `packages/server/src/api/routes/tests/static.spec.ts:218-235` confirms this behavior. The test authenticates as a BASIC role user and successfully generates a signed upload URL, verifying HTTP 200 and a defined `res.body.signedUrl`. ## Remediation 1. Restore the `authorized(BUILDER)` middleware on the route 2. Add `paramResource("datasourceId")` to ensure the datasource belongs to the caller's app 3. Pin the S3 bucket to `datasource.config.bucket` in the controller, ignoring the caller-supplied bucket value
Why it matters now
SSVC decision points
Not available: CISA has not published SSVC decision points for this record.
Affected products
| Vendor | Product | Affected versions | Fixed in | Status | Source |
|---|---|---|---|---|---|
| — | @budibase/server (npm) | up to 3.38.1 | — | No fix listed | GHSA-xcx6-4f2g-hhgx |
- @budibase/server (npm) Vendor— Affected up to 3.38.1 Fixed in — No fix listed GHSA-xcx6-4f2g-hhgx
Remediation
No fixed version listed by the sources yet.
Timeline
- 2026-10-03 Threatist record created from GHSA-xcx6-4f2g-hhgx
References
Sources
This product uses the NVD API but is not endorsed or certified by the NVD. Sources and licences