Get a quote

Authorization and tenant isolation

How we test that every role can do only what it should, and that one customer organisation can never reach another's data, using a role matrix and at least two test tenants.

8 min readStandards: OWASP API Security Top 10 2023: API1 BOLA, API3 BOPLA, API5 BFLA · OWASP ASVS 5.0: Authorization chapter · OWASP WSTG: Authorization testing category · CWE-639 Authorization Bypass Through User-Controlled Key, CWE-285 Improper Authorization

Test areas

Role matrix4 checks

  • Every sensitive action attempted as every in-scope role
  • Vertical access: lower roles calling higher-role actions directly
  • Role changes taking effect immediately, including for existing sessions
  • Invitations and role assignment limited to the right inviters

Object-level authorization4 checks

  • Every identifier a client can supply checked for ownership
  • Reads, updates, deletes and exports tested separately
  • Nested and related objects, such as comments on another tenant's record
  • Bulk and batch endpoints that accept lists of identifiers

Property-level authorization3 checks

  • Fields a role can see but should not, in responses and exports
  • Fields a role can set but should not, through mass assignment
  • Hidden or computed fields returned by default

Tenant isolation5 checks

  • Two or more test tenants exercised against each other
  • Search, reporting and analytics that aggregate across tenants
  • Signed file URLs, attachments and generated documents
  • Background jobs, webhooks and notifications routed to the right tenant
  • Caches keyed by tenant as well as by user

Administrative boundaries3 checks

  • Internal admin consoles reachable only by staff roles
  • Support impersonation recorded and limited
  • Organisation admin actions confined to their own organisation

Why this chapter matters most

In most modern SaaS products, the most damaging finding is not an exotic injection. It is a correctly signed-in user receiving a record that belongs to someone else. Authorization has to be decided correctly on every endpoint, for every object, for every role, and it is easy for one new endpoint to forget. Enterprise reviewers know this, which is why tenant isolation appears on almost every security questionnaire.

The role matrix

Before testing starts we build a matrix. Rows are roles in a tenant: anonymous visitor, member, billing admin, organisation admin, internal staff. Columns are the actions that matter: read an invoice, invite a user, change a plan, export data, call an admin API. Each cell has an expected answer, agreed with your team.

Testing then fills the matrix with observed answers using real accounts. Disagreements are findings. Cells we could not test, because an account was missing or a feature was unavailable, are recorded as gaps in the coverage record rather than silently skipped.

Object, function and property checks

Object-level checks ask whether the server confirms that the requested object belongs to the caller. We test reads, updates, deletes and exports separately, because they are often implemented in different places. Related objects get the same treatment: a comment, an attachment or a line item can leak even when its parent is protected.

Function-level checks ask whether an action is allowed for the caller’s role at all, even when the interface hides the button. Property-level checks look at individual fields: data returned that the role should not see, and fields accepted on update that the role should not be able to set, such as a role or account status.

A synthetic illustration

In the sample report, a member of Tenant A requests an invoice identifier issued to Tenant B on api.example.com and receives it in full. The endpoint checked that the caller was signed in, but not that the invoice belonged to their organisation. The fix scopes the lookup by tenant in the data-access layer, so every caller of that query inherits the check.

Tenant isolation beyond the obvious endpoints

Isolation failures often hide in places the main interface does not show: global search, reporting dashboards, scheduled exports, generated PDFs, signed download links, webhooks and notification emails. We test each with two or more tenants, and we look at caches that might serve one tenant’s response to another.

What evidence looks like

Each finding names the two accounts involved, the role and tenant of each, the request, and the part of the response that proves the boundary was crossed. Evidence uses synthetic tenants and documentation domains. Where a boundary held under deliberate testing, the coverage record says so, because “we tried and it held” is exactly what a reviewer wants to see.

Fixes that remove the class

The most useful remediation moves the check to a place every caller passes through: tenant-scoped repositories, policy objects, row-level security or a central authorization service. We also recommend an automated test per sensitive endpoint that requests another tenant’s object and expects denial, so the same flaw does not return with the next feature.

What this chapter does not cover

  • Coverage depends on test accounts for every role and at least two tenants; missing accounts reduce coverage and are recorded.
  • Grey-box testing infers server-side logic from behaviour; source code review can find authorization gaps that behaviour does not reveal.
  • Tenant data in production that differs from the test environment is not covered unless production testing is agreed.
  • Authorization inside third-party services the product calls is out of scope.

Get a fixed quote for your release.

A short form about the product and the deadline. We reply with scoping questions, then a fixed written quote.