
Every multi-tenant SaaS platform has a tenant boundary, and every one of them enforces it correctly in the obvious places. Nobody ships a product where logging in as tenant A shows tenant B’s dashboard. That is not where isolation fails.
It fails in the features built later, by different people, under time pressure, where the tenant context was assumed rather than enforced.
The seven places we consistently find it
1. Search and filtering
The main listing endpoint scopes correctly by tenant. The search endpoint hits a different index, or a different query builder, and the tenant predicate is missing. Search is frequently added after the core product and frequently bypasses the ORM layer that carries the scoping.
2. Export and reporting
Exports often run asynchronously as a background job. The job receives an object ID and a filter set, and executes without the request context that carried the tenant identity. We routinely find export jobs that will happily generate a CSV of another tenant’s records if the job parameters are manipulated.
3. Bulk and batch endpoints
A single-item endpoint checks authorisation on the item. The bulk version accepts an array of IDs and checks the first one, or checks none, on the assumption that the UI only ever submits IDs the user can see.
4. File and document access
Uploaded files are stored with a predictable path or a signed URL with an over-long lifetime and an over-broad scope. The application enforces tenant isolation; the storage layer does not.
5. Webhooks and callbacks
Webhook payloads are constructed from the object, not from the subscriber’s permitted view. We have seen webhooks that include fields the receiving tenant should never see, and webhook subscription endpoints that allow one tenant to subscribe to events in another.
6. Administrative and support tooling
Support staff need cross-tenant visibility by design. The question is whether that capability is properly gated — and whether an ordinary user can reach the support role’s endpoints by calling them directly. Internal tooling is often built on the same API with a different front end, and the API does not always know the difference.
7. Identifier leakage across the boundary
Autocomplete, mention features, sharing dialogs, error messages and analytics endpoints that return identifiers from outside the caller’s tenant. The object may be protected, but the existence and identifier of that object is itself information.
What testing requires
Two tenants. Two accounts at every permission level in each. This is not a preference, it is a precondition — with a single tenant, cross-tenant isolation cannot be tested at all, and any report claiming to have assessed it is claiming something it cannot support.
Beyond the accounts, the method is systematic replay: every request captured as tenant A is replayed with tenant B’s session, and vice versa, across every role pairing. It is slow and it is the only thing that works.
The architectural answer
Tenant scoping belongs in one place, applied by default, resolved from the session rather than from anything the client sends. The strongest implementations we assess make it impossible to write a query that omits the tenant predicate — the data access layer will not construct one.
The weakest — and the most common — make tenant scoping a thing each developer remembers to do. That approach does not fail on the day it is written. It fails eighteen months later, in the seventh feature, when someone is in a hurry.