Cross-tenant leakage is documented, not theoretical
Cross-tenant exposure is a recurring, high-severity failure class, and it happens to the most sophisticated vendors. The root cause is almost always a broken logical boundary, a missing filter, a bypassable policy, a shared credential or a cache key without tenant scope, rather than broken encryption.
The AI era already has its canonical case. OpenAI attributed the March 2023 ChatGPT incident to a Redis client bug where canceled requests could return another user’s cached data (tracked as CVE-2023-28858 and CVE-2023-28859). That is the textbook cache-key-missing-tenant-scope leak. Wiz Research has catalogued the same class at the cloud-platform level.
| Incident | Platform | Root cause (per source) |
|---|---|---|
| ChatGPT Redis bug (2023) | OpenAI | Cache key without tenant scope returned another user’s data |
| DeepSeek ClickHouse (2025) | DeepSeek | Publicly reachable database, unauthenticated SQL (Wiz) |
| ChaosDB (2021) | Azure Cosmos DB | Notebook feature to host root to other tenants’ keys (Wiz) |
| ExtraReplica (2022) | Azure PostgreSQL | Over-permissive certificate regex allowed cross-account access (Wiz) |
| AttachMe (2022) | Oracle OCI | Volume-attach API required no permission check (Wiz) |
| Hell’s Keychain (2022) | IBM Cloud PostgreSQL | Plaintext secrets plus push-scoped registry credentials (Wiz) |
The pattern reads as a warning to any pooled design. OWASP ranks Broken Object Level Authorization as the top API risk, which is the same cross-tenant failure at the API layer: change one identifier and read another customer’s object. None of these needed a novel cryptographic break. Each needed one logical boundary to be skippable.
The isolation problem: why one tenant seeing another is an existential bug
Start with the threat model. In a multi-tenant data platform you owe every customer three guarantees. Confidentiality: tenant B cannot read tenant A's data. Integrity: tenant B cannot modify it. Availability: tenant B cannot starve tenant A of resources. A single failure on the first guarantee can end a company. In a pooled model, a single missed WHERE clause or a misconfigured row-level security policy is all it takes to turn shared infrastructure into a data-leak incident.
You have three architectural choices.
Logical isolation (pooled). All tenants share the same tables. A tenant_id column plus row-level security enforces the boundary. This is the cheapest model and the simplest to scale: one connection pool, one migration path, one backup strategy. A single database can hold an enormous number of tenants. The risk is that your entire isolation guarantee rests on a predicate being applied correctly on every query.
Physical isolation (siloed). Each tenant gets its own schema, database, or warehouse. This is the strongest boundary and the easiest compliance story. It is also the most expensive: costs rise roughly linearly with every customer, and operational overhead (backups, monitoring, patching, connection management) multiplies. It works for dozens to hundreds of tenants, not tens of thousands. More than one SaaS company has watched a per-tenant database strategy turn into an unsustainable cloud bill.
Hybrid (bridge). Shared compute and network with dedicated data or identity for sensitive tenants. Enforcement moves up the stack, from the storage engine to the query planner. This is where a semantic layer earns its place.
| Model | Database mapping | Isolation strength | Cost and scale |
|---|---|---|---|
| Silo (physical) | Database per tenant | Strongest; smallest blast radius | Most expensive; tens of tenants |
| Bridge (hybrid) | Schema per tenant | Strong data separation, shared compute | Middle ground |
| Pool (logical) | Shared table, tenant_id | Logical only; largest blast radius | Cheapest; thousands of tenants |
AWS’s own Well-Architected SaaS Lens is blunt about the pooled model: the tenant boundary is enforced logically, and crossing it in any form would be a significant and potentially unrecoverable event for a SaaS business. The cheaper the model, the more the isolation depends on enforcement that runs every time, correctly.
Here is the part most teams underestimate. Even when your rows are perfectly isolated, meaning is not. Consider two tenants on the same platform. Both have Customers, Revenue, Churn, and Subscriptions. Underneath, the definitions diverge. Revenue includes refunds for tenant A and excludes them for tenant B. Churn is measured over 30 days for one and 90 days for another. If an AI agent or a shared metric service resolves "revenue last quarter" against the wrong tenant's definition, no row ever crossed a boundary and the answer is still wrong. Isolation is therefore two problems stacked: keep the data apart, and keep the definitions apart.
Why database row-level security alone is insufficient
Row-level security is excellent and you should use it. It is also not a complete answer for a customer-facing SaaS platform. Walk through how it actually works in the four systems most teams run.
PostgreSQL RLS. You enable a policy that appends a predicate to every query automatically:
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
ALTER TABLE invoices FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
USING (tenant_id = current_setting('app.current_tenant')::uuid);
The application sets the context per transaction:
BEGIN;
SET LOCAL app.current_tenant = '8b3a3b3a-0c07-4ef9-8db6-9c1f0b111234';
SELECT * FROM invoices; -- silently filtered to this tenant
COMMIT;
SET LOCAL matters: it scopes the variable to the transaction so a pooled connection never leaks a previous request's tenant. The footguns are well documented. A role with BYPASSRLS or a view owned by a superuser skips the policy entirely. Forget WITH CHECK and you can write rows no tenant can read. Leave the context unset on a pooled connection and you either see nothing or, worse, the wrong tenant. And the database enforces the row boundary, not the meaning of a metric.
Snowflake. Row access policies and dynamic data masking are evaluated at query runtime. Snowflake's own multi-tenancy guidance for Cortex Agents pairs immutable session attributes with row access policies and is explicit that this is a "shared responsibility model": Snowflake provides the tools, and you are responsible for configuring them correctly. Performance is not free either: a row access policy adds a predicate to every query, and "On tables with 100M+ rows, this can add 10-30% overhead depending on the policy complexity," unless the policy column aligns with the clustering key.
Databricks Unity Catalog. Row filters and column masks are SQL UDFs, now backed by attribute-based access control policies, governed tags, and automated classification. Unity Catalog fails securely: on unsupported runtimes "no data is returned." Strong governance, but the unit of control is the table and column, not a per-tenant metric definition.
BigQuery. Authorized views for row filtering, native row-level security policies, and column-level security through Data Catalog policy tags. Again, all enforced at the data layer.
Every one of these enforces isolation at runtime, on the data, after a query has been formed. They share three structural weaknesses for SaaS at scale. First, they trust that the right tenant context was set on the right connection. Second, they protect rows and columns but not the business meaning layered on top. Third, the audit trail begins after the query runs, so reconstructing exactly what each tenant could see means exhaustive runtime logging.
How a semantic layer enforces isolation at compile time
A semantic layer sits between your users, your AI agents, and your warehouse. Instead of running a query and trimming the result, it resolves the request against a model of your business, evaluates tenant context, and decides what is allowed before any SQL exists. The difference is the order of operations: policy shapes the plan, then the plan compiles to SQL, then the SQL runs.
Concretely, compile-time enforcement does four things.
It resolves meaning within scope. A well-formed multi-tenant semantic model defines meaning across layered scopes: a Global scope for invariant concepts (what a Customer is), a Tenant scope for business-specific definitions (what Revenue means here), a Persona scope for role-based interpretation (Finance vs Product), and a User scope for individual context. Revenue stops being one global definition and becomes a scoped object:
{
"concept": "Revenue",
"scope": {
"tenant_A": "SUM(order_amount - refunds)",
"tenant_B": "SUM(order_amount)"
}
}
The same natural-language question compiles to different SQL per tenant. That closes the semantic-leakage gap that pure row filters cannot touch.
It shapes an allowed subgraph before planning. The requester's identity and persona resolve a slice of the model they are permitted to traverse. Compilation happens entirely inside that slice. If a metric depends on a node outside the allowed scope, resolution fails. There is no query to run, no row to trim, no masked column to leak through a join key. This is the inversion of post-hoc masking, which trusts that every query runner remembered to apply the masking view, every BI tool refreshed its column list, and every analyst followed the policy.
It proves joins on the graph. A persona without access to one side of a relationship cannot use it as a join key. Ambiguous or unauthorized join paths fail compilation rather than silently producing a wrong or over-broad number.
It produces a deterministic, auditable result. Given the same tenant context, the same query, and the same model version, the output is identical. The audit record captures the model version, the identity context, the resolved definitions, the proven join paths, and the compiled SQL. The same question asked tomorrow against the same model version reproduces the same answer and the same trail.
A worked example: A support engineer for tenant B issues "show me refund totals by customer." In a pure-RLS world, the generated SQL joins orders to refunds, the row filter scopes rows to tenant B, but the refund table was never tagged sensitive for the support persona, so the column comes back in full. No cross-tenant leak, but a within-tenant policy bypass, and the auditor finds it months later. At compile time, the refund metric is outside the support persona's allowed subgraph, resolution fails, and the failure itself is logged with full tenant and persona context. The control is structural, not procedural.
Tenant context still has to get there. The semantic layer reads identity from JWT claims, session attributes, or a security context propagated through its APIs (Colrows accepts tenant identity over MCP, HTTP, and JDBC). This is the honest boundary of the approach.
How AI agents leak data across tenants
Agents make a pooled schema more dangerous in three specific ways, and none of them is a jailbreak.
The full schema in the prompt. The common text-to-SQL pattern feeds the model a large slice of the schema. Research on schema-inference attacks (arXiv:2406.14545, NAACL Findings 2025) shows models leak table and column names even from nonsensical inputs, and recommends prompting the model with only the schema elements the caller is allowed to see. If a shared-schema agent has other tenants’ table names in context, it can construct a cross-tenant query.
Machine speed. An agent runs queries automatically, so a single mis-scoped template replicated across thousands of runs turns one bug into thousands of exposures. The safer pattern is a curated, schema-first context surface rather than a blank cheque to write ad-hoc SQL.
Service-account tenancy collapse. When an agent connects as one shared service account, the database cannot tell which tenant is really asking, and the agent inherits that account’s broad access. This is the confused-deputy problem, and letting the model fill in the tenant identifier is the sharpest form of it: getting the tenant wrong exposes an entire organisation’s data at once. We covered the enforcement side of this in how to secure AI agent database access.
The measurements are stark. A 2026 benchmark of text-to-SQL under role-based access control (arXiv:2607.22115, an arXiv preprint) found strong open-weight models violating access rules on 63.77 percent of instances on the BIRD dataset, even when handed the rules, through a refusal-cliff where the model reasons correctly that access should be denied yet still emits a query that returns the data. On the retrieval side, a 2026 study of multi-tenant enterprise retrieval reported that ungated vector search leaks cross-tenant data in 98 to 100 percent of probes, because similarity search is global by default. You cannot rely on the model to scope itself, which is why the answer is to make the wrong query uncompilable, the same reasoning behind point-in-time query reproducibility.
Fix the Context, Not the Model. A well-governed semantic layer that understands business context creates more reliable AI-driven analytics than fine-tuning the model itself. Tenant isolation is context. No amount of model tuning stops an agent that can see another tenant’s fields in its prompt.
The trade-offs, quantified
Cost. Logical isolation is the cheapest infrastructure and pushes the cost into policy evaluation. Physical isolation can be roughly 10 to 100 times more expensive at scale and guarantees no leakage. Semantic isolation adds a compile step that is cheaper than per-row runtime filtering and pays for itself in audit.
Performance. Snowflake row access policies can add 10 to 30 percent overhead on tables of 100M or more rows. PostgreSQL RLS, benchmarked at 50M rows across 10K tenants, averaged about 0.3ms of policy evaluation with composite indexes and "two orders of magnitude slower" without them, with the SET LOCAL call adding under 0.1ms. The lesson is identical across engines: index the tenant key, or pay for it on every query.
Scale. Logical and sharded models scale to thousands or millions of tenants. Physical isolation scales to dozens, maybe low hundreds, before operational overhead and cost dominate.
Security. The weak points of logical isolation are all configuration: a BYPASSRLS role, a stale tenant context on a pooled connection, a missing WITH CHECK, a wrong identity passed into the query. Compile-time policy reduces the blast radius because an unauthorized plan is never generated, but it does not remove your responsibility for authentication and credential isolation.
Audit complexity. Pure logical isolation requires exhaustive runtime logging to reconstruct what each tenant saw. Compile-time enforcement logs the policy decision and the compiled plan at the moment of compilation, which is a smaller, cleaner, and reproducible record.
Why regulators are about to make this table stakes
Every major framework converges on a single question: can you prove Customer B never saw Customer A's data, even in a join, even in an aggregate?
PCI DSS. Appendix A1 of PCI DSS v4.0, retitled from Shared Hosting Providers to cover Software as a Service, sets requirements for multi-tenant service providers. Effective 31 March 2025, A1.1.1 requires logical separation between customer environments, and A1.1.4 requires confirming that separation with penetration testing at least every six months. These additional requirements for multi-tenant service providers, is now mandatory under the active version of the standard (v4.0.1, the sole supported version since 31 December 2024). A1.1 requires that "Multi-tenant service providers protect and separate all customer environments and data." A1.1.2 requires controls "such that each customer only has permission to access its own cardholder data and CDE," and A1.1.4 (effective 31 March 2025) requires confirming the effectiveness of logical separation controls via penetration testing every six months. A1.2.1 requires per-customer audit logs available for review only by the owning customer. Logical separation is explicitly acceptable, but you must prove it works.
FedRAMP. Built on NIST 800-53, with SC-7 Boundary Protection, SC-3 Security Function Isolation, and SC-39 Process Isolation. Multi-tenant logical separation is permitted at Moderate and High when controls demonstrably enforce isolation, and a 2025 update (RFC-0013) modernized SC-7 to recognize VPCs and security groups rather than only Layer 3 subnetting. The recurring theme: demonstrable enforcement, not a diagram.
HIPAA. The Audit Controls standard, 45 CFR 164.312(b), requires mechanisms that "record and examine activity in information systems that contain or use" ePHI, and 164.312(a)(2)(i) requires a unique user ID per accessor. Multi-tenant systems must keep PHI from leaking between tenants and must produce a tenant-scoped audit trail. Enforcement settlements repeatedly cite organizations that logged access but never reviewed it: Memorial Healthcare System paid $5.5M in 2017, with OCR stressing that "organizations must implement audit controls and review audit logs regularly," and Excellus Health Plan paid $5.1M in 2021 over a failure to implement information-system-activity review and access controls.
SOX 404. Internal control over financial reporting rests on IT general controls: access management, change management, and segregation of duties. As one summary puts it, you must "demonstrate the chain of custody for every number." A multi-tenant analytics platform serving financial data has to show that access is segregated by tenant and that every definition and policy change is versioned and attributed.
GDPR. Article 17 (right to erasure) and Article 20 (right to data portability, in a "structured, commonly used and machine-readable format") both require operating at tenant and data-subject scope. You must be able to delete or export one customer's data without touching another's.
Commercial stakes reinforce the compliance ones. In a LogRhythm and Dimensional Research survey of 1,175 security professionals, 67 percent said their company had lost a business deal over a customer’s lack of confidence in their security. Buyer questionnaires such as the Cloud Security Alliance CAIQ ask directly how tenant environments are logically separated and how data commingling is prevented, so isolation you cannot evidence is a deal you may not close.
The common thread is that database row filters give you enforcement but not evidence. Compile-time policy decisions, versioned alongside business definitions and logged with tenant context, give you both. As data becomes a customer-facing product tier, with Salesforce and Snowflake shipping bidirectional data sharing and B2B buyers asking every vendor whether "Salesforce, Stripe, and Segment connect to my data warehouse, can you do that too?", the vendors that can prove isolation will win the regulated accounts and the rest will be stuck at the procurement gate.
Where Colrows fits, and where it does not
Colrows is a semantic execution layer. It compiles enterprise intent into governed, deterministic, dialect-perfect SQL, and it enforces tenant isolation in the planner before SQL is emitted. In a multi-tenant context that means four things.
First, tenant definitions and policies are scoped to tenant identity and versioned alongside business semantics in a typed graph, so the meaning of a metric is isolated, not just its rows. Second, governance is compile-time: RBAC, ABAC, and row and column predicates shape the allowed subgraph, and unauthorized plans are never generated. Colrows starts from default-deny, deny rules always win, and policies bind to classes (pii, financial, regulated) rather than table names that drift. Third, tenant context flows through MCP, HTTP, and JDBC, and enforcement happens before any database is touched. Fourth, isolation is deterministic: the same tenant, query, and model version yield the same result and the same audit record, which captures the graph version, the identity context, the resolved definitions, the proven join paths, and the compiled SQL. That record is the artifact a HIPAA, SOX, or PCI auditor actually wants.
Now the honest scope. Colrows governs data semantics in a multi-tenant context. It is not a complete multi-tenancy solution and does not replace your database engine's controls. The application is still responsible for propagating the correct tenant identity into the layer, and for credential isolation and authentication. Colrows enforces at the query-planning layer, not inside the storage engine, so it complements row-level security, masking, and physical separation rather than removing the need for them. Defense in depth still applies: keep your database row filters as a backstop, keep authentication and key management at the application edge, and use the semantic layer to enforce meaning and policy at compile time and to produce the deterministic audit trail.
The takeaway for builders: isolation works as a stack. Storage keeps the rows apart. The semantic layer keeps the definitions apart and proves, at compile time and in an auditable record, that what executed is exactly what was authorized. As customer-facing data products spread and multi-tenant regulation tightens, that proof is becoming the price of entry.
Frequently asked questions
Is database row-level security enough for multi-tenant SaaS isolation?
No. Row-level security enforces the row boundary at runtime, after a query has already been formed. It trusts that the right tenant context was set on the right connection, it protects rows and columns but not business meaning, and its audit trail begins only after the query runs.
What is semantic leakage in a multi-tenant system?
It is when the rows stay isolated but the definitions do not. Two tenants can share concepts like Revenue or Churn with divergent definitions (refunds included for one, excluded for the other), so a shared metric service that resolves a question against the wrong tenant's definition returns a wrong answer without any row crossing a boundary.
How does a semantic layer enforce tenant isolation at compile time?
It resolves the request against tenant-scoped definitions (Global, Tenant, Persona, User), shapes an allowed subgraph before planning, proves join paths on the graph, and only then compiles SQL. Unauthorized plans are never generated, and each compilation produces a deterministic, auditable record.
What is the performance overhead of row-level security at scale?
Snowflake row access policies can add 10 to 30 percent overhead on tables of 100M or more rows. PostgreSQL RLS, benchmarked at 50M rows across 10K tenants, averaged about 0.3ms of policy evaluation with composite indexes and was two orders of magnitude slower without them. Index the tenant key or pay for it on every query.
How much more expensive is physical tenant isolation than logical isolation?
Physical isolation can be roughly 10 to 100 times more expensive at scale. It works for dozens to low hundreds of tenants before cost and operational overhead dominate, while logical and sharded models scale to thousands or millions of tenants.
How do AI agents leak data across tenants?
In three ways, none of which is a jailbreak. The full schema is often placed in the prompt, so an agent can see and reference other tenants’ table names. Agents run at machine speed, so one mis-scoped template repeats across thousands of runs. And agents commonly connect as a shared service account, so the database cannot tell which tenant is asking and the agent inherits broad access. A 2026 RBAC benchmark measured models violating access rules on up to 63.77 percent of instances even when handed the rules.
What is the confused-deputy problem for AI agents?
A confused deputy is a program tricked into misusing its own authority for someone with less. An agent runs with the access of the account it connects under, so if it reads attacker-controlled or cross-tenant content, it can be steered to use that access to reach data the requester should never see. Letting the model choose the tenant identifier is the sharpest version, because getting the tenant wrong exposes an entire organisation’s data at once.
Which regulations require proof of multi-tenant isolation?
PCI DSS v4.0.1 Appendix A1 mandates separated customer environments with penetration testing of logical separation every six months. FedRAMP requires demonstrable isolation under NIST 800-53. HIPAA requires tenant-scoped audit trails, and SOX 404 and GDPR add per-tenant segregation, erasure, and portability duties.
