Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources or documents need attention: 261/275 feeds/APIs · 469/469 docs · 9/9 advisories · checked 18:30 UTC Customize Public modeDiscuss ChangeIntel on Discord

Budibase: S3 presigned URL endpoint authorization regression in v3.39.4 allows BASIC users to obtain S3 PutObject presigned URLs

Exact source revision recorded 24 Oct 2026 13:17:17 UTC. It does not establish the source's current position. Latest evidence.

osv · GHSA-xcx6-4f2g-hhgx

Published

## 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

Source published
24 Jul 2026 21:17:03 UTC
Source modified
15 Aug 2026 05:19:24 UTC
Observed here
24 Oct 2026 13:17:17 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N

Publisher rating · HIGH

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 10 Nov 18:30 UTC · 261 of 275 readable · 260 fully read · documentation 469/469 current