Seat Limit Bypass in Multi-Tenant Apps: More Members Than You Paid For
Seat limits are authorization wearing a billing costume. The UI says "3 of 3 seats used." The API might still accept member number four.
Multi-tenant apps make this worse because invites, SSO just-in-time users, service accounts, and guests often skip the same counter.
Count what the bill counts
Start on a plan with a low cap. Invite until you hit the wall. Then try paths that are not the invite modal:
POST /tenants/{id}/memberswith a raw email- Accepting an invite created before the cap
- Re-activating a deactivated user
- Adding a bot, integration, or "guest" role
- SSO login that auto-provisions outside the invite flow
- Copying a member via workspace clone or template
Race two invite accepts when one seat remains. Both callbacks may succeed if the counter increments after provision.
Check whether removed users free seats slowly—soft-delete windows sometimes let you add a new member while the old one still has access, temporarily overrunning the license. That still matters if both sessions work.
Tenants, children, and shadow seats
Parent accounts with child workspaces may enforce seats only on the parent. Create members in a child project and see whether they consume the parent pool. Sub-accounts that inherit enterprise features without inheriting enterprise counters are a frequent miss.
Also inspect tokens already issued. A seat bypass is stronger when the fourth user can call privileged APIs, not merely appear grayed-out in the directory. Log in as that user and hit a paid feature endpoint.
SCIM provisioning and CSV bulk-import are frequent blind spots. If you can upload three emails on a two-seat plan and all three activate, the import path skipped the counter the invite UI uses.
I treat view-only licenses carefully: if the plan sells view-only as a separate SKU and you mint unlimited viewers, say so. Do not inflate severity by counting users the product intentionally leaves uncapped—read the pricing page.
Proof for billing and security reviewers
Provide tenant ID, plan name, stated seat cap, member list before/after, and a request that added the extra seat. Show the over-cap user exercising a gated action. If the admin UI still shows "3/3" while four accounts work, call out the desync; that helps developers find the missing server check.
Remediation belongs in the membership transaction: count active seats under lock, refuse provision when active >= licensed, include bots if they are billable, and reconcile SSO provisioning with the same counter.
Pending invites can also cheat the math. Fill all seats, create pending invites anyway, free one seat, then accept two pending invites in parallel. If both land, the cap was never part of the accept transaction.
API keys and machine users sometimes sit outside the human seat counter while still consuming billable capacity the pricing page describes as "seats." If the docs sell seats inclusively, overage via bots is in scope.
Seat bypasses are quiet money bugs. No payload fireworks—just one extra human inside the plan fence.