Foundations

Multi-Tenancy & Data Isolation

Intermediate

In a multi-tenant system, the single most important rule is that one tenant can never see or touch another's data. There is no acceptable rate of cross-tenant leakage. A single case is a reportable breach. Make the tenant boundary something the system enforces by design, on every path, not something each query must remember to add.

Multi-tenancy is efficient because tenants share infrastructure, code, and often tables. It is dangerous for the same reason: the only thing separating customers is correct tenant scoping, applied without exception. The goal is to make isolation the default and a leak the hard thing to write, rather than relying on every developer to add a tenant filter every time.

The tenant identity must always come from the validated security context, never from the request, and it must reach every read, write, and delete of tenant-owned data. The Finperiti shared-HS256-secret finding is a multi-tenancy risk in disguise: a single shared signing key undermines the very identity that tenant isolation depends on.

Isolate by construction

Guard the whole surface

Tenant-blind cache key var key = $"customer:{customerId}";
return cache.GetOrAdd(key, () => Load(customerId)); // no tenant in key or query

Two tenants with colliding ids, or a shared id space, get each other's data straight from the cache, bypassing any database scoping entirely.

Tenant in every key and query var t = ctx.TenantId; // from validated context
var key = $"{t}:customer:{customerId}";
return cache.GetOrAdd(key, () =>
db.QuerySingleOrDefault("... WHERE Id=@id AND TenantId=@t", new { id = customerId, t }));

The tenant is part of both the cache key and the query predicate, so isolation holds end to end.

Self-review checklist

Why it matters: Cross-tenant leakage is one of the most serious failures a SaaS platform can have: an instant, reportable breach of confidentiality that destroys customer trust and invites regulatory action. Because the boundary is invisible until it is crossed, isolation has to be enforced by design and tested on purpose, not left to be remembered query by query.