Learn

What is multi-tenant privilege escalation?

Multi-tenant privilege escalation lets a user cross into another tenant or gain a higher role. Learn the impact, the blind spots, and how to prevent it.

Updated 2026-10-15

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.

Questions

What is a tenant?

A tenant is one customer account in a shared app, usually a company or workspace. Many tenants share the same code and often the same database.

Is this different from IDOR?

IDOR is one way it happens. Tenant escalation also covers role changes, invite flows and admin tools that let a user gain power inside or across tenants.

Does database-per-tenant solve it?

It reduces the blast radius, but the routing layer that picks the database can still be wrong. You still need tenant checks in application code.

See it on your app.