CVE-2026-45717
Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL.
Budibase is an open-source low-code platform. Prior to 3.38.1, Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check. As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports. This vulnerability is fixed in 3.38.1.
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
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.8
Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL.
Budibase is an open-source low-code platform. Prior to 3.38.1, Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check. As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports. This vulnerability is fixed in 3.38.1.
- Record
CVE-2026-45717- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-32601
8.8
Budibase is an open-source low-code platform. Prior to 3.38.1, Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check. As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports. This vulnerability is fixed in 3.38.1.
- Record
EUVD-2026-32601- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-44m2-crh7-f4q2
8.8
Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL
Summary
Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check.
As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports.
Code evidence
Route registration — wrong authorization group
packages/server/src/api/routes/datasource.ts, line 35-37
authorizedRoutes
.get("/api/datasources/:datasourceId", datasourceController.find)
.put("/api/datasources/:datasourceId", datasourceController.update) // <-- should be builderRoutes
All destructive (create/delete/verify) operations are gated behind builderRoutes:
builderRoutes
.get("/api/datasources", datasourceController.fetch)
.post("/api/datasources/verify", datasourceController.verify)
.post("/api/datasources", datasourceValidator(), datasourceController.save)
.delete("/api/datasources/:datasourceId/:revId", datasourceController.destroy)
The update route shares the same authorization group as the read route, not the builder group.
Authorization middleware allows BASIC-role users
packages/server/src/middleware/authorized.ts, lines 46-50
packages/backend-core/src/security/permissions.ts, lines 82-90
packages/backend-core/src/security/roles.ts, lines 162-169
authorizedRoutes is defined with authorized(PermissionType.TABLE, PermissionLevel.READ).
When doesHaveBasePermission(TABLE, READ, rolesHierarchy) is evaluated for a BASIC-role user:
BASICrole →BuiltinPermissionID.WRITEWRITEpermission includesPermissionImpl(PermissionType.TABLE, PermissionLevel.WRITE)getAllowedLevels(WRITE)returns[WRITE, READ]- Therefore
TABLE/READis satisfied → user is authorized
BASIC is the lowest non-public authenticated built-in role. Any end-user account added to a Budibase app will be assigned at minimum the BASIC role.
Controller performs no additional builder check
packages/server/src/api/controllers/datasource.ts, lines 207-255
export async function update(ctx) {
const db = context.getWorkspaceDB()
const datasourceId = ctx.params.datasourceId
const baseDatasource = await sdk.datasources.get(datasourceId) // no builder guard
await invalidateVariables(baseDatasource, ctx.request.body)
const dataSourceBody: Datasource = isBudibaseSource
? { name: ..., type: ..., source: SourceName.BUDIBASE }
: ctx.request.body // attacker-controlled config
let datasource: Datasource = {
...baseDatasource,
...sdk.datasources.mergeConfigs(dataSourceBody, baseDatasource), // merges attacker config
}
const response = await db.put(sdk.tables.populateExternalTableSchemas(datasource)) // persisted
...
}
mergeConfigs does not protect non-password connection fields
packages/server/src/sdk/workspace/datasources/datasources.ts, lines 278-316
mergeConfigs only replaces PASSWORD_REPLACEMENT sentinel values back to the stored secret. Fields like host, port, database, url, ssl are taken from the update payload without restriction:
// update back to actual passwords for everything else
for (let [key, value] of…
- Record
GHSA-44m2-crh7-f4q2- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
NVD
8.8
Budibase is an open-source low-code platform. Prior to 3.38.1, Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check. As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports. This vulnerability is fixed in 3.38.1.
- Record
CVE-2026-45717- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSV
8.8
Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL.
Budibase is an open-source low-code platform. Prior to 3.38.1, Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check. As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports. This vulnerability is fixed in 3.38.1.
- Record
CVE-2026-45717- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
OSVGHSA-44m2-crh7-f4q2
8.8
Budibase: `PUT /api/datasources/:datasourceId` is protected only by `TABLE/READ` permission instead of builder access, allowing any authenticated app user to overwrite datasource connection parameters including host, port, and URL
Summary
Budibase exposes a REST API for datasource management. The route PUT /api/datasources/:datasourceId is registered in the authorizedRoutes group with TABLE/READ permission. This is the same authorization level as the read endpoint (GET /api/datasources/:datasourceId). Every authenticated Budibase app user with the BASIC built-in role or higher carries TABLE/WRITE (and therefore TABLE/READ) permissions, and the datasource update controller performs no additional builder check.
As a result, any authenticated non-builder app user can submit a PUT request to rewrite a datasource's config object — including the connection host, port, database credentials, or the base url of a REST datasource. Because no network-level SSRF protection is applied to SQL driver connections, redirecting a PostgreSQL/MySQL/MongoDB datasource to an internal IP address succeeds and the attacker can probe or interact with internal services on arbitrary ports.
Code evidence
Route registration — wrong authorization group
packages/server/src/api/routes/datasource.ts, line 35-37
authorizedRoutes
.get("/api/datasources/:datasourceId", datasourceController.find)
.put("/api/datasources/:datasourceId", datasourceController.update) // <-- should be builderRoutes
All destructive (create/delete/verify) operations are gated behind builderRoutes:
builderRoutes
.get("/api/datasources", datasourceController.fetch)
.post("/api/datasources/verify", datasourceController.verify)
.post("/api/datasources", datasourceValidator(), datasourceController.save)
.delete("/api/datasources/:datasourceId/:revId", datasourceController.destroy)
The update route shares the same authorization group as the read route, not the builder group.
Authorization middleware allows BASIC-role users
packages/server/src/middleware/authorized.ts, lines 46-50
packages/backend-core/src/security/permissions.ts, lines 82-90
packages/backend-core/src/security/roles.ts, lines 162-169
authorizedRoutes is defined with authorized(PermissionType.TABLE, PermissionLevel.READ).
When doesHaveBasePermission(TABLE, READ, rolesHierarchy) is evaluated for a BASIC-role user:
BASICrole →BuiltinPermissionID.WRITEWRITEpermission includesPermissionImpl(PermissionType.TABLE, PermissionLevel.WRITE)getAllowedLevels(WRITE)returns[WRITE, READ]- Therefore
TABLE/READis satisfied → user is authorized
BASIC is the lowest non-public authenticated built-in role. Any end-user account added to a Budibase app will be assigned at minimum the BASIC role.
Controller performs no additional builder check
packages/server/src/api/controllers/datasource.ts, lines 207-255
export async function update(ctx) {
const db = context.getWorkspaceDB()
const datasourceId = ctx.params.datasourceId
const baseDatasource = await sdk.datasources.get(datasourceId) // no builder guard
await invalidateVariables(baseDatasource, ctx.request.body)
const dataSourceBody: Datasource = isBudibaseSource
? { name: ..., type: ..., source: SourceName.BUDIBASE }
: ctx.request.body // attacker-controlled config
let datasource: Datasource = {
...baseDatasource,
...sdk.datasources.mergeConfigs(dataSourceBody, baseDatasource), // merges attacker config
}
const response = await db.put(sdk.tables.populateExternalTableSchemas(datasource)) // persisted
...
}
mergeConfigs does not protect non-password connection fields
packages/server/src/sdk/workspace/datasources/datasources.ts, lines 278-316
mergeConfigs only replaces PASSWORD_REPLACEMENT sentinel values back to the stored secret. Fields like host, port, database, url, ssl are taken from the update payload without restriction:
// update back to actual passwords for everything else
for (let [key, value] of…
- Record
GHSA-44m2-crh7-f4q2- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-862
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@budibase/servernpm |
before 3.38.1 | 3.38.1 |
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-45717 is a high vulnerability (CVSS 8.8) in Budibase, published May 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in @budibase/server 3.38.1.
References
github.com/Budibase/budibase/security/advisories/GHSA-44m2-crh7-f4q2
github.com/Budibase/budibase/releases/tag/3.38.1
nvd.nist.gov/vuln/detail/CVE-2026-45717
github.com/advisories/GHSA-44m2-crh7-f4q2
github.com/CVEProject/cvelistV5/tree/main/cves/2026/45xxx/CVE-2026-45717.json
github.com/Budibase/budibase
Left out here: the rest of 2 source descriptions. The JSON record has them.