Skip to content

fix: prevent blocked admins from retaining access - #27

Merged
Megasley merged 1 commit into
Megasley:mainfrom
comwanga:fix/issue-23-admin-moderation
Sep 8, 2026
Merged

fix: prevent blocked admins from retaining access#27
Megasley merged 1 commit into
Megasley:mainfrom
comwanga:fix/issue-23-admin-moderation

Conversation

@comwanga

@comwanga comwanga commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #23.

Suspended or banned administrators could retain a valid Supabase session and continue calling administrative server actions. Because the admin authorization gate checked only authentication and role, a blocked admin could potentially restore their own account.

What changed

1. Require an active account for privileged access

  • requireAdmin() now runs requireActiveAccount() before checking the admin role.
  • Suspended and banned accounts are rejected even when their existing access token is still valid.
  • Partner and organization-invite admin actions now reuse the hardened central admin gate.
  • Admin and review pages also apply the active-account gate so blocked accounts cannot continue reading privileged queues through stale sessions.

2. Revoke sessions on suspension and ban

  • Suspending or banning an account deletes all of that user's rows from Supabase's auth.sessions table.
  • The account-status update and session revocation run in one database transaction.
  • If session revocation fails, the status update is rolled back rather than returning a partially applied moderation result.
  • Session revocation applies to both suspended and banned accounts.

3. Protect administrator recovery paths

  • Administrators cannot suspend or ban their own account.
  • The last active administrator cannot be suspended or banned.
  • These checks live in the repository layer, so they protect every caller rather than relying on the UI.
  • Server actions return specific, actionable error messages for both cases.

Security outcome

The original self-restore path is closed at multiple layers:

  1. A suspended or banned admin cannot pass requireAdmin().
  2. An admin cannot suspend or ban themselves in the first place.
  3. Suspended and banned users lose all refreshable Supabase sessions.
  4. Existing short-lived access tokens remain harmless for privileged operations because account status is checked on every privileged request.

Verification

  • npm test — 129 tests passed
  • npx tsc --noEmit --pretty false
  • ESLint on all changed files
  • Prettier check on all changed files
  • git diff --check

I also added focused regression tests covering suspended and banned admin rejection, active non-admin rejection, and active admin access.

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

@comwanga is attempting to deploy a commit to the Megasley Team on Vercel.

A member of the Team first needs to authorize it.

@comwanga
comwanga marked this pull request as ready for review September 8, 2026 18:41
@Megasley

Megasley commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Thank you very much!

Reviewed and verified independently, tests (129/129) and typecheck pass in an isolated worktree, and the three fix layers (active-account gate, session revocation, self/last-admin guard) are correctly wired end-to-end. Merging.

Two follow-ups to track separately, neither blocking: the last-admin check has a TOCTOU race (unlocked count read outside the transaction) under concurrent admin actions, and the new repository-layer logic (self/last-admin, session revocation) has no test coverage yet.

Closes #23.

@Megasley
Megasley merged commit 1a7ccf0 into Megasley:main Sep 8, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

suspended or banned admins can retain administrative access

2 participants