@@ -7,6 +7,7 @@ import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
77import { WorkspaceUser } from '../database/entities/workspace-user.entity'
88import { WorkspaceUserService } from '../services/workspace-user.service'
99import {
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