Skip to content
Authreads
Back to all articles

Security / Multi-Tenant · 7 min read

How Tenant Isolation Should Be Enforced, and How to Tell Whether a Vendor Really Does It

Tenant isolation claims are universal; the mechanism behind them isn't. How isolation should be enforced, and the one question that reveals whether a vendor actually does it.

Published

Illustrative photo for the article How Tenant Isolation Should Be Enforced, and How to Tell Whether a Vendor Really Does It

The promise every multi-tenant vendor makes

'Your data is isolated from other tenants' appears, in some phrasing, on almost every multi-tenant vendor's security page. It is close to a universal claim, which makes it close to useless as a way of comparing vendors, because the sentence is true of almost every system in the ordinary case, and the interesting question is never about the ordinary case. The interesting question is what happens on the day someone writes a query that forgets to ask for it.

This matters more for an identity platform than for almost any other kind of multi-tenant system, because the data in question isn't a customer's product data: it's the credentials, sessions, and access records that decide who gets into everything else. A cross-tenant leak in a project-management tool exposes task titles. A cross-tenant leak in an identity platform exposes the mechanism that controls access to every other system those credentials touch. The stakes of the same architectural question scale with what the system is actually holding.

Three places isolation can live

Tenant isolation can be enforced in roughly three places, and they are not equivalent. The first is application-layer discipline: every function that touches tenant data is written by a developer who remembers to include a tenant filter. This is the most common approach because it requires no special infrastructure, and it is also the most fragile, because it depends on every developer, on every code path, remembering every time. The second is framework-layer scoping: a request-scoped context object carries the current tenant, and helper functions thread it through automatically so an individual query doesn't need to restate it by hand. This removes some of the manual burden, but the isolation still lives in code that a new endpoint, a background job, or an internal admin tool can simply route around, deliberately or by accident.

The third is enforcement as a property of the storage itself: isolation evaluated on every read and every write, regardless of which code path issued the query, so that a query which fails to specify a tenant does not fall back to 'all tenants' by omission. This is the meaningfully different option, not because it's more sophisticated engineering, but because of what happens when someone forgets. Under the first two models, a missed filter is a cross-tenant data leak. Under the third, a missed filter is a query that returns nothing, or is rejected outright, because the absence of a tenant identifier was never treated as equivalent to 'no restriction.' The safety doesn't depend on a developer's memory on a Friday afternoon; it depends on a property that holds regardless of who wrote the query or why.

The honest test: what happens when someone forgets

This is the single most informative question you can ask a vendor about isolation, because it's the one scenario every real engineering organization has actually lived through. New engineers ship code. Deadlines compress code review. Someone writes a new internal tool at short notice to unblock a support ticket. If the answer to 'what happens when a query is written without a tenant filter' involves careful code review, a linter rule, or 'we'd catch that in testing,' you are looking at application-layer isolation with a human backstop: real, but fallible, because it depends on the backstop actually catching the specific mistake, every time, forever. If the answer is that the query returns nothing, or fails outright, because the isolation doesn't trust the query to have specified itself correctly, you are looking at isolation enforced independent of the code that asked for the data. Those are different guarantees, and only one of them survives a bad Friday.

The paths nobody thinks to ask about

Vendors that can answer confidently about their main product API often go quiet about the paths around it. Background jobs that process records in bulk for billing or analytics. Data exports built for a specific customer request and never generalized. Support tooling that lets an operator look up an account by email across the whole system, because building a tenant-scoped support tool is more work than building an unscoped one. Webhook delivery pipelines. Log aggregation, where a debug line written to help diagnose one tenant's issue ends up in a shared stream readable by whoever has log access. None of these are the system the vendor demos. All of them are places where the discipline that holds on the primary API can quietly not apply, because they were built later, by a different team, under time pressure, without the same review.

A genuine isolation claim covers these paths, not just the one a sales engineer walks you through. It's worth asking directly whether internal tooling (support consoles, admin panels, ad hoc scripts operators run) goes through the same isolation boundary as the customer-facing product, or a separate, broader-access path that exists precisely because internal users are trusted more than the boundary is trusted.

The objection worth taking seriously

The standard argument against enforcing isolation at the storage layer is performance: a check that runs on every single read and write, without exception, sounds like it should be slower than trusting application code to have already scoped the query correctly. In practice this gets the trade backwards. The check is a narrow, well-defined comparison evaluated as part of normal query execution, not an external call or a second round trip: the cost is closer to an additional filter than to a separate service being consulted. What actually gets expensive is the alternative: a leak discovered after the fact, which triggers a full audit of every code path that ever touched the affected data, a customer notification process, and in the worst case a regulatory one. Measured honestly, the performance cost of enforcement is a rounding error next to the cost of a breach it would have prevented.

What isolation doesn't cover

It's worth being precise about the boundary of this guarantee, because 'tenant isolation' is sometimes stretched to imply more than it does. Isolation prevents one tenant's request from reaching another tenant's data. It says nothing on its own about who within a tenant can see what: that's authorization, a separate control operating one layer up, and a vendor can have airtight tenant isolation with a genuinely weak permission model inside each tenant. It also says nothing about data at rest being unreadable to someone with direct storage access outside the application entirely, which is a different property again. A vendor that leads with 'isolated' as though it's the whole security story is answering a narrower question than the one most buyers are actually asking. Ask about all three (isolation between tenants, authorization within a tenant, and protection of data outside the application layer) because a strong answer to one doesn't imply a strong answer to the others.

Questions worth asking instead of features to accept

A useful evaluation doesn't take 'we enforce tenant isolation' as an answer; it asks for the mechanism and the failure mode. Is isolation enforced as a property of the storage layer, or only in the application code written against it? What is the observable behavior of a query that omits a tenant identifier: does it error, does it return an empty result, or does it silently execute unscoped? Do internal support and admin tools authenticate through the same isolation boundary as the product API, or a separate path with broader visibility? Is there a documented boundary for asynchronous and background processing specifically, since that's where scoping discipline erodes first? And, most usefully if you can get it: can the vendor show you, in a sandbox, what a cross-tenant attempt actually does, rather than describe what it's supposed to do?

Isolation posture is architecture, not a policy statement

Every vendor will tell you tenant data is isolated. The ones worth trusting with it can tell you, specifically, where that guarantee is enforced, what happens on the day a human forgets, and which of their own internal tools they trust less than the boundary itself. That specificity is the actual product being sold when a vendor talks about isolation: not the sentence on the security page, but the architecture that makes the sentence true even when nobody's watching.