Multi-tenant privilege escalation is when a user in a shared (multi-tenant) app gains access they should not have, either by reaching another tenant's data or by raising their own role. A member becomes an admin, or a user in one company sees another company's workspace. It is a form of broken access control, often tied to improper privilege management (CWE-269).
Updated October 2026
Why it matters
In a SaaS product, the tenant boundary is the promise you make to every customer: your data stays yours. A single crossing breaks that promise for all of them at once, because the same code serves everyone. One customer's employee reading a competitor's records is the kind of incident that ends contracts.
Role escalation inside a tenant matters too. If a guest can make themselves an admin, they can invite others, change billing, export data and remove the real owners.
A simple illustration
Acme Corp sells a workspace product. Each workspace has admins, members and guests. Admins can change a user's role from a settings page. The server checks that the caller is an admin, but it does not check that the target user is in the caller's workspace, and it does not stop an admin from granting roles in a workspace they do not belong to.
Vulnerable check:
def set_role(caller, target_user_id, new_role):
if caller.role != "admin":
raise Forbidden()
target = User.get(target_user_id)
target.role = new_role
target.save()
Corrected check:
def set_role(caller, target_user_id, new_role):
target = User.get(target_user_id)
if target is None or target.tenant_id != caller.tenant_id:
raise NotFound()
if caller.role_in(caller.tenant_id) != "admin":
raise Forbidden()
if new_role not in ALLOWED_ROLES:
raise BadRequest()
target.role = new_role
target.save()
The fix checks the tenant of the target, checks the caller's role in that same tenant, and validates the requested role against a fixed list.
Why automated scanners often miss it
Scanners usually run inside one account. They never see a second tenant, so they cannot notice that data or roles leak between tenants. Role changes also need context: the tool has to know that a guest should not reach a settings action, and that an admin in tenant A has no power in tenant B. That model of intended access lives in your product design, not in the HTTP traffic.
How to prevent it
- Carry the tenant ID in the server-side session, never trust it from the client.
- Apply tenant filters in a shared data layer, or use database row-level security as a second guard.
- Check the caller's role within the tenant of the target object, not a global role.
- Restrict which roles each role may grant. Members should never grant admin.
- Review invite, transfer, SSO join and support tools, which often bypass normal checks.
- Separate internal staff tools from customer-facing APIs.
How to test your own app for it
Only test software you own or have written permission to test.
- Create at least two test tenants, each with admin, member and guest accounts.
- Confirm no account in one tenant can read or change anything in the other.
- Confirm each role can only grant roles at or below the allowed level.
- Review every place a tenant ID enters the system and confirm it comes from the session.
- Check background jobs, webhooks and exports for missing tenant filters.
How Wakefield helps
Wakefield's blackbox agents sign in as every role your app has (admin, member, guest), map its pages and APIs, build a model of who should see what, then try to cross user, tenant and role lines. A separate verifier replays each finding with a live exploit and a negative control, so you only see bugs that reproduce. See Blackbox testing.