Problem
create_invitations_impl in crates/services/src/organization/mod.rs (line 681) only checks can_manage_members() before creating invitations. This returns true for both owners and admins, meaning an admin can invite users with the owner role — a privilege escalation.
Expected
The backend should enforce that users can only invite with roles equal to or lower than their own:
- Owner can invite as: owner, admin, member
- Admin can invite as: admin, member
- Member cannot invite (already enforced)
Where to fix
In create_invitations_impl (line 712 loop), before creating each invitation, check that the requester's role is sufficient for the requested invitation role. For example:
// Inside the for (email, role) in invitations loop:
if role == MemberRole::Owner && org.owner_id != requester_id {
// Non-owners cannot invite as owner
}
Or more generally, fetch the requester's role once before the loop and compare against each invitation's role.
Current mitigation
The frontend filters the role dropdown based on the inviter's role (ROLE_HIERARCHY in invite-members-dialog.tsx), but this is client-side only and can be bypassed via API calls.
Problem
create_invitations_implincrates/services/src/organization/mod.rs(line 681) only checkscan_manage_members()before creating invitations. This returnstruefor both owners and admins, meaning an admin can invite users with theownerrole — a privilege escalation.Expected
The backend should enforce that users can only invite with roles equal to or lower than their own:
Where to fix
In
create_invitations_impl(line 712 loop), before creating each invitation, check that the requester's role is sufficient for the requested invitation role. For example:Or more generally, fetch the requester's role once before the loop and compare against each invitation's role.
Current mitigation
The frontend filters the role dropdown based on the inviter's role (
ROLE_HIERARCHYininvite-members-dialog.tsx), but this is client-side only and can be bypassed via API calls.