Problem
In crates/web/src/components/member_list.rs:178, the admin permission check uses get_untracked():
let is_admin = app_state.server.admin_ids.get().contains(&peer_id.get_untracked());
This reads the admin set at click-time but the signal may be stale if the user's admin status was just revoked. A user who was recently un-admined could trigger Trust/Untrust/Kick actions in the window before the UI reflects the change.
The server-side apply_unchecked() will reject unauthorized actions, but the client still builds and broadcasts the event, wasting network resources and creating confusion.
Impact
- Stale UI state allows clicking admin-only buttons after revocation
- Server rejects the action but user sees no immediate feedback
- Not a security vulnerability (server validates) but a UX/consistency issue
Suggested fix
Use reactive get() instead of get_untracked() for permission checks, and disable buttons reactively when admin status changes.
Location
crates/web/src/components/member_list.rs:178
References
Found during deep implementation audit (pass 2)
Problem
In
crates/web/src/components/member_list.rs:178, the admin permission check usesget_untracked():This reads the admin set at click-time but the signal may be stale if the user's admin status was just revoked. A user who was recently un-admined could trigger Trust/Untrust/Kick actions in the window before the UI reflects the change.
The server-side
apply_unchecked()will reject unauthorized actions, but the client still builds and broadcasts the event, wasting network resources and creating confusion.Impact
Suggested fix
Use reactive
get()instead ofget_untracked()for permission checks, and disable buttons reactively when admin status changes.Location
crates/web/src/components/member_list.rs:178References
Found during deep implementation audit (pass 2)