You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
GET /api/datasources/{datasourceId}/structure has no per object authorization, so any authenticated user can read the full database schema of a data source owned by another organization, and with ignoreCache=true force a live connection that uses the owner's stored credentials.
Root cause
DatasourceController.getStructure calls the structure service directly with no permission check, while every sibling single data source route gates on checkCurrentUserManageDatasourcePermission.
server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/datasource/DatasourceController.java (around line 113):
Contrast getById (around line 63) which routes through datasourceApiService.findByIdWithPermission, and update/delete which check permission. The structure service does not re compute authorization either:
privateMono<DatasourceStructure> getLatestAndSave(StringdatasourceId) {
returndatasourceService.getById(datasourceId) // no organization or permission filter
...
}
DatasourceServiceImpl.getById is a plain repository.findById, and the route sits under the blanket /api/** to .authenticated() rule, so any logged in member of any organization reaches it.
Impact
Cross organization disclosure of another org's database schema (tables, columns, types, keys), and with ignoreCache=true a live connection to the owner's database using the owner's stored credentials. CWE-639, CWE-862.
Fix
Apply the same checkCurrentUserManageDatasourcePermission (or an equivalent org scoped permission check) to getStructure before resolving the data source, as the sibling routes do.
Activity