- Shipped
- September 23, 2026 at 12:35 PM UTC
- Author
- Kamo
- Commit
- 80ec053
Five gaps let a signed-in member reach outside their own organization, or reach a colleague's account, with no right check: - **************** resolved no session at all. The gateway forwards /api/security/** with no auth of its own, so anyone holding a role UUID could rewrite or delete any organization's role rights. createRole resolved an org but no right, so any member could pre-load a new role with arbitrary rights. All three now require CONFIGURE_SYSTEM (or an open god window) and, for update/delete, that the role belongs to the caller's org — the same rule DepartmentController and JobTitleController already enforce on their own write paths, on the same essential-settings page. - **************** never resolved the caller's organization, so an owner of org A could set org B's access level or owner status by member id alone; getMemberAccess checked only that a session existed. Both now scope the target to the caller's org (getMemberAccess keeps its previous breadth for a same-org read). updateMemberAccess also read a session key ("MID") that KSessionService never writes, so every real call threw and 500'd before reaching either the old vulnerable code or the new check; fixed in the same edit so the org-scoping fix is actually reachable. **************** (kamo-shared-library, already pushed) gets the same organization check as defense in depth. - **************** let any same-org member rewrite a colleague's **************** with no right check — USER_IDENTITY_FIELDS covers only the fields that live on the User account (name/DOB/phonetic), and these live on Member instead. members.email doubles as a login and password-recovery identifier **************** and the recovery flow emails the reset link to whatever address was TYPED on the form rather than the account's own address, so this was a path to redirecting where a colleague's password reset link is delivered. Gated on isSelf || MANAGE_MEMBER_SECURITY, mirroring kamo-internal's own selfOrSecurityAdmin gate on the sibling usernameAlias field. - LeadCreditController /credits/distribute and /credits/allotments org-checked teamMemberId but loaded vendorId/vendorProductId (and, in createAllotment, marketId) by findById alone, so a UUID from another organization's lead-vendor catalogue or market configuration worked as well as the caller's own. Same org-equality check as the team-member case (via the vendor's organization; a product via its vendor; a market via its own organization), same 404 response. One test class per surface, each with a case that fails without its fix (mutation- checked: reverted, confirmed red, restored) plus a same-org success case so legitimate callers going through the real kamo-internal screens (essential settings' roles tab, the member profile's security/access tabs, Manage Credits) still succeed.
