CVE-2026-50136
Budibase: Unauthenticated S3 signed upload URL generation allows arbitrary writes with stored datasource credentials
Budibase is an open-source low-code platform. Prior to 3.39.3, the application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values. This vulnerability is fixed in 3.39.3.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
7.4
Budibase: Unauthenticated S3 signed upload URL generation allows arbitrary writes with stored datasource credentials
Budibase is an open-source low-code platform. Prior to 3.39.3, the application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values. This vulnerability is fixed in 3.39.3.
- Record
CVE-2026-50136- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - Weakness
- CWE-306
- Updated
- 2026-11-02
EUVDEUVD-2026-39912
7.4
Budibase is an open-source low-code platform. Prior to 3.39.3, the application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values. This vulnerability is fixed in 3.39.3.
- Record
EUVD-2026-39912- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-jj36-r9w3-3pfh
7.4
Budibase: Unauthenticated S3 signed upload URL generation allows arbitrary writes with stored datasource credentials
The application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values.
Details
The static route registers the signed upload URL endpoint with only recaptcha before the controller:
packages/server/src/api/routes/static.ts:44-48
44: .post(
45: "/api/attachments/:datasourceId/url",
46: recaptcha,
47: controller.getSignedUploadURL
48: )
The controller loads the datasource by datasourceId with enriched secret values:
packages/server/src/api/controllers/static/index.ts:590-598
590:export const getSignedUploadURL = async function (
591: ctx: Ctx<GetSignedUploadUrlRequest, GetSignedUploadUrlResponse>
592:) {
593: // Ensure datasource is valid
594: let datasource
595: try {
596: const { datasourceId } = ctx.params
597: datasource = await sdk.datasources.get(datasourceId, { enriched: true })
598: if (!datasource) {
The request body controls bucket and key, and the server signs a PUT URL using the stored datasource credentials:
packages/server/src/api/controllers/static/index.ts:609-629
609: if (datasource?.source === "S3") {
610: const { bucket, key } = ctx.request.body || {}
611: if (!bucket || !key) {
612: ctx.throw(400, "bucket and key values are required")
613: }
614: try {
615: let endpoint = datasource?.config?.endpoint
616: if (endpoint && !utils.urlHasProtocol(endpoint)) {
617: endpoint = `https://${endpoint}`
618: }
619: const s3 = new S3({
620: region: awsRegion,
621: endpoint: endpoint,
622: credentials: {
623: accessKeyId: datasource?.config?.accessKeyId as string,
624: secretAccessKey: datasource?.config?.secretAccessKey as string,
625: },
626: })
627: const params = { Bucket: bucket, Key: key }
628: signedUrl = await getSignedUrl(s3, new PutObjectCommand(params))
629: if (endpoint) {
The endpoint returns the signed URL and public URL to the caller:
packages/server/src/api/controllers/static/index.ts:630-639
630: publicUrl = `${endpoint}/${bucket}/${key}`
631: } else {
632: publicUrl = `https://${bucket}.s3.${awsRegion}.amazonaws.com/${key}`
633: }
634: } catch (error: any) {
635: ctx.throw(400, error)
636: }
637: }
638:
639: ctx.body = { signedUrl, publicUrl }
Because no authorization middleware is applied, the API trusts public input to choose where the stored S3 credentials will write.
PoC
Non-destructive validation approach:
- Create or identify a workspace with an S3 datasource.
- Obtain the production workspace ID and S3 datasource ID.
- Send an unauthenticated request with the workspace ID header and attacker-controlled bucket/key:
POST /api/attachments/<datasourceId>/url HTTP/1.1
x-budibase-app-id: app_<workspace-id>
content-type: application/json
{"bucket":"attacker-controlled-or-permitted-bucket","key":"poc/budibase.txt"}
- Observe that the response contains a signed PUT URL.
- Upload harmless content to the returned
signedUrland confirm the object is created using the datasource's stored S3 credentials.
Impact
This allows unauthenticated arbitrary object writes wherever the stored S3 datasource credentials have PutObject access. Depending on the datasource permissions, this can corrupt application data, overwrite public assets, place attacker-controlled objects in trusted buckets, consume storage, or abuse an organization's cloud credentials.
- Record
GHSA-jj36-r9w3-3pfh- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - Weakness
- CWE-306
- Updated
- 2026-11-02
NVD
7.4
Budibase is an open-source low-code platform. Prior to 3.39.3, the application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values. This vulnerability is fixed in 3.39.3.
- Record
CVE-2026-50136- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - CVSS 3.1
- 5.3 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N - Weakness
- CWE-306
- Updated
- 2026-11-02
OSV
7.4
Budibase: Unauthenticated S3 signed upload URL generation allows arbitrary writes with stored datasource credentials
Budibase is an open-source low-code platform. Prior to 3.39.3, the application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values. This vulnerability is fixed in 3.39.3.
- Record
CVE-2026-50136- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - Weakness
- CWE-306
- Updated
- 2026-11-02
OSVGHSA-jj36-r9w3-3pfh
7.4
Budibase: Unauthenticated S3 signed upload URL generation allows arbitrary writes with stored datasource credentials
The application server exposes an unauthenticated endpoint that generates S3 PutObject presigned URLs using credentials stored in a workspace datasource. The route is protected only by the recaptcha middleware and does not require authentication, table permission, datasource permission, or builder access. A public caller who knows a workspace ID and S3 datasource ID can request a signed upload URL for attacker-controlled bucket and key values.
Details
The static route registers the signed upload URL endpoint with only recaptcha before the controller:
packages/server/src/api/routes/static.ts:44-48
44: .post(
45: "/api/attachments/:datasourceId/url",
46: recaptcha,
47: controller.getSignedUploadURL
48: )
The controller loads the datasource by datasourceId with enriched secret values:
packages/server/src/api/controllers/static/index.ts:590-598
590:export const getSignedUploadURL = async function (
591: ctx: Ctx<GetSignedUploadUrlRequest, GetSignedUploadUrlResponse>
592:) {
593: // Ensure datasource is valid
594: let datasource
595: try {
596: const { datasourceId } = ctx.params
597: datasource = await sdk.datasources.get(datasourceId, { enriched: true })
598: if (!datasource) {
The request body controls bucket and key, and the server signs a PUT URL using the stored datasource credentials:
packages/server/src/api/controllers/static/index.ts:609-629
609: if (datasource?.source === "S3") {
610: const { bucket, key } = ctx.request.body || {}
611: if (!bucket || !key) {
612: ctx.throw(400, "bucket and key values are required")
613: }
614: try {
615: let endpoint = datasource?.config?.endpoint
616: if (endpoint && !utils.urlHasProtocol(endpoint)) {
617: endpoint = `https://${endpoint}`
618: }
619: const s3 = new S3({
620: region: awsRegion,
621: endpoint: endpoint,
622: credentials: {
623: accessKeyId: datasource?.config?.accessKeyId as string,
624: secretAccessKey: datasource?.config?.secretAccessKey as string,
625: },
626: })
627: const params = { Bucket: bucket, Key: key }
628: signedUrl = await getSignedUrl(s3, new PutObjectCommand(params))
629: if (endpoint) {
The endpoint returns the signed URL and public URL to the caller:
packages/server/src/api/controllers/static/index.ts:630-639
630: publicUrl = `${endpoint}/${bucket}/${key}`
631: } else {
632: publicUrl = `https://${bucket}.s3.${awsRegion}.amazonaws.com/${key}`
633: }
634: } catch (error: any) {
635: ctx.throw(400, error)
636: }
637: }
638:
639: ctx.body = { signedUrl, publicUrl }
Because no authorization middleware is applied, the API trusts public input to choose where the stored S3 credentials will write.
PoC
Non-destructive validation approach:
- Create or identify a workspace with an S3 datasource.
- Obtain the production workspace ID and S3 datasource ID.
- Send an unauthenticated request with the workspace ID header and attacker-controlled bucket/key:
POST /api/attachments/<datasourceId>/url HTTP/1.1
x-budibase-app-id: app_<workspace-id>
content-type: application/json
{"bucket":"attacker-controlled-or-permitted-bucket","key":"poc/budibase.txt"}
- Observe that the response contains a signed PUT URL.
- Upload harmless content to the returned
signedUrland confirm the object is created using the datasource's stored S3 credentials.
Impact
This allows unauthenticated arbitrary object writes wherever the stored S3 datasource credentials have PutObject access. Depending on the datasource permissions, this can corrupt application data, overwrite public assets, place attacker-controlled objects in trusted buckets, consume storage, or abuse an organization's cloud credentials.
- Record
GHSA-jj36-r9w3-3pfh- CVSS 3.1
- 7.4 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L - Weakness
- CWE-306
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@budibase/servernpm |
before 3.39.2 | 3.39.2 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-50136 is a high vulnerability (CVSS 7.4) in Budibase, published June 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.29%, the 21st percentile. Fixed in @budibase/server 3.39.2.
References
github.com/Budibase/budibase/security/advisories/GHSA-jj36-r9w3-3pfh
github.com/Budibase/budibase/pull/18774
github.com/Budibase/budibase/commit/d9dbb7f6105373cc88ecacdbcab70c776f7dd6a1
nvd.nist.gov/vuln/detail/CVE-2026-50136
github.com/advisories/GHSA-jj36-r9w3-3pfh
github.com/CVEProject/cvelistV5/tree/main/cves/2026/50xxx/CVE-2026-50136.json
github.com/Budibase/budibase