Skip to content

Commit b7a2005

Browse files
authored
fix: access to invited workspace (#6360)
* fix: access to invited workspace * update: idor guards
1 parent 9c85c14 commit b7a2005

1 file changed

Lines changed: 19 additions & 10 deletions

File tree

packages/server/src/enterprise/controllers/workspace-user.controller.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
77
import { WorkspaceUser } from '../database/entities/workspace-user.entity'
88
import { WorkspaceUserService } from '../services/workspace-user.service'
99
import {
10+
assertMayReadTargetUser,
1011
assertQueryOrganizationMatchesActiveOrg,
1112
assertWorkspaceIdAccessibleToUser,
1213
getLoggedInUser,
@@ -35,35 +36,43 @@ export class WorkspaceUserController {
3536

3637
let workspaceUser: any
3738
if (query.workspaceId && query.userId) {
39+
// Caller must have access to the workspace (own, assigned, or org admin within their org).
3840
await assertWorkspaceIdAccessibleToUser(user, query.workspaceId, queryRunner)
3941
workspaceUser = await workspaceUserService.readWorkspaceUserByWorkspaceIdUserId(
4042
query.workspaceId,
4143
query.userId,
4244
queryRunner
4345
)
4446
} else if (query.workspaceId) {
47+
// Caller must have access to the workspace (own, assigned, or org admin within their org).
4548
await assertWorkspaceIdAccessibleToUser(user, query.workspaceId, queryRunner)
4649
workspaceUser = await workspaceUserService.readWorkspaceUserByWorkspaceId(query.workspaceId, queryRunner)
4750
} else if (query.organizationId && query.userId) {
51+
// organizationId must match the caller's active org to prevent cross-org access.
52+
// Caller must be the target user or an org user manager whose target belongs to the same org (IDOR guard).
4853
assertQueryOrganizationMatchesActiveOrg(user, query.organizationId)
49-
if (query.userId !== user.id && !userMayManageOrgUsers(user)) {
50-
throw new InternalFlowiseError(StatusCodes.FORBIDDEN, GeneralErrorMessage.FORBIDDEN)
51-
}
54+
await assertMayReadTargetUser(user, query.userId, queryRunner)
5255
workspaceUser = await workspaceUserService.readWorkspaceUserByOrganizationIdUserId(
5356
query.organizationId,
5457
query.userId,
5558
queryRunner
5659
)
5760
} else if (query.userId) {
58-
if (query.userId !== user.id && !userMayManageOrgUsers(user)) {
59-
throw new InternalFlowiseError(StatusCodes.FORBIDDEN, GeneralErrorMessage.FORBIDDEN)
61+
if (query.userId === user.id) {
62+
// Self-lookup: return memberships across all orgs so the user can switch to an invited org/workspace.
63+
workspaceUser = await workspaceUserService.readWorkspaceUserByUserId(query.userId, queryRunner)
64+
} else {
65+
// Non-self: caller must be an org user manager and the target must belong to the caller's active org (IDOR guard).
66+
// Results are scoped to the caller's active org to prevent cross-org data leakage.
67+
await assertMayReadTargetUser(user, query.userId, queryRunner)
68+
workspaceUser = await workspaceUserService.readWorkspaceUserByOrganizationIdUserId(
69+
user.activeOrganizationId,
70+
query.userId,
71+
queryRunner
72+
)
6073
}
61-
workspaceUser = await workspaceUserService.readWorkspaceUserByOrganizationIdUserId(
62-
user.activeOrganizationId,
63-
query.userId,
64-
queryRunner
65-
)
6674
} else if (query.roleId) {
75+
// Only org user managers may list workspace members by role.
6776
if (!userMayManageOrgUsers(user)) {
6877
throw new InternalFlowiseError(StatusCodes.FORBIDDEN, GeneralErrorMessage.FORBIDDEN)
6978
}

0 commit comments

Comments
 (0)