Recording an observation for the platform to rule on — I could not tell from the outside whether this is intended.
A user whose org role is member can read every invitation row of the organization through the data API, including invitations addressed to other people: their email address, the role they are being granted, and the inviter.
Repro (measured)
Org 甲 has two invitations: lisi@ (member, accepted) and wangwu@ (admin, pending). lisi@ is a plain member of that org.
As lisi@, with the active organization set to 甲:
awaitfetch('/api/v1/auth/organization/get-active-member')// → { role: "member" }awaitfetch('/api/v1/data/sys_invitation')// → 200, total: 2// [ { email: "lisi@acme-test.com", role: "member", status: "accepted" },// { email: "wangwu@acme-test.com", role: "admin", status: "pending" } ]Identical to what the org owner sees. Full rows also carry inviter_id and expires_at.
For contrast, the same member is correctly denied elsewhere:
GET /api/v1/data/sys_permission_set
→ 403 [Security] Access denied: operation 'find' on object 'sys_permission_set'
is not permitted for positions [org_member, everyone]
so object-level gating is in force generally — sys_invitation is simply readable by org_member.
Why it might matter
A pending invitation is administrative intent, not a colleague directory: it exposes the addresses of people who are not yet (and may never become) members, and discloses who is about to be made an admin. Membership (sys_member / the members page) is a different question — that one reads like a legitimate staff directory.
The decision
Either confirm org_member read on sys_invitation is intended (in which case this issue is just documentation), or narrow it — e.g. restrict to owner/admin, or row-scope it to email = current_user.email so a member can still see their own invitation.
Related UI-side finding: #8092 (the members page shows invite/remove affordances to member; the server does gate those writes).
Environment
Local dev server http://localhost:8080, multi-org enabled, observed 2026-08-12. The server was started by the maintainer and its exact commit is not verified.
Recording an observation for the platform to rule on — I could not tell from the outside whether this is intended.
A user whose org role is
membercan read every invitation row of the organization through the data API, including invitations addressed to other people: their email address, the role they are being granted, and the inviter.Repro (measured)
Org 甲 has two invitations:
lisi@(member, accepted) andwangwu@(admin, pending).lisi@is a plainmemberof that org.As
lisi@, with the active organization set to 甲:Identical to what the org owner sees. Full rows also carry
inviter_idandexpires_at.For contrast, the same member is correctly denied elsewhere:
so object-level gating is in force generally —
sys_invitationis simply readable byorg_member.Why it might matter
A pending invitation is administrative intent, not a colleague directory: it exposes the addresses of people who are not yet (and may never become) members, and discloses who is about to be made an admin. Membership (
sys_member/ the members page) is a different question — that one reads like a legitimate staff directory.The decision
Either confirm
org_memberread onsys_invitationis intended (in which case this issue is just documentation), or narrow it — e.g. restrict toowner/admin, or row-scope it toemail = current_user.emailso a member can still see their own invitation.Related UI-side finding: #8092 (the members page shows invite/remove affordances to
member; the server does gate those writes).Environment
Local dev server
http://localhost:8080, multi-org enabled, observed 2026-08-12. The server was started by the maintainer and its exact commit is not verified.