You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(auth): close last-admin TOCTOU (count + mutate admins in one transaction) #919
The last-admin protection has a time-of-check/time-of-use race. checkLastAdminConstraint (used by UpdateUser) and DeleteUser both run CountGroupMembers in the service layer, then perform the UpdateUser/DeleteUser write in a separate statement with no surrounding transaction or row lock. There is no DB-level "≥1 Administrators member" constraint (only the per-user cardinality(group_ids) >= 1 CHECK).
Two concurrent privileged requests, each removing a different one of the last two admins, can both observe count == 2, both pass the guard, and leave the system with zero admins.
Severity is LOW (narrow window, requires two simultaneous privileged actors), but the outcome (no admins) is unrecoverable without DB surgery.
Surfaced by the post-merge security review of #912 (2026-06-02), finding LOW-1.
Fix options
Perform the count + mutation inside a single transaction with SELECT ... FOR UPDATE on the Administrators-group members, OR
Add a deferred DB constraint / trigger enforcing at least one Administrators-group member.
Add a regression test exercising concurrent removal of the last two admins.
Activity
fix(auth): make last-admin trigger race-safe, active-aware, and narro…
fix(auth): close last-admin TOCTOU with deferred DB trigger (closes #919
fix(auth): make last-admin trigger race-safe, active-aware, and narro…
fix(auth): renumber migration, cut UpdateUser complexity, add DB-leve…
fix(auth): close last-admin TOCTOU with deferred DB trigger (#921)