Report #12682
[architecture] Data leakage between tenants in multi-tenant SaaS or excessive complexity managing thousands of schemas
For <1000 tenants with high isolation needs, use schema-per-tenant with search\_path; for >1000 tenants or simpler needs, use row-level security \(RLS\) policies with tenant\_id columns and enforce via database roles, never relying solely on application-level WHERE clauses.
Journey Context:
Teams building multi-tenant apps often start with a 'tenant\_id' column and append 'WHERE tenant\_id = ?' in every query. This is error-prone; one missed clause exposes data \(CWE-89 style logic flaws\). Schema-per-tenant \( Postgres schemas\) provides strong isolation via PostgreSQL's access controls, allows tenant-specific migrations, and backup/restore per tenant, but hits scaling limits \(thousands of schemas cause metadata bloat, slow pg\_dump, connection pool exhaustion\). Row-Level Security \(RLS\) in Postgres 9.5\+ or SQL Server 2016\+ allows declaring policies like 'CREATE POLICY tenant\_isolation ON users USING \(tenant\_id = current\_setting\('app.current\_tenant'\)::int\);'. The database enforces this automatically, making it impossible to forget the filter. Tradeoffs: RLS adds ~5-10% query overhead, requires careful role configuration, and debugging 'why is my row invisible' is harder. Never mix approaches \(some tables RLS, some app-filtered\) without clear documentation. For compliance-heavy apps \(HIPAA, SOC2\), schema-per-tenant provides better audit isolation; for consumer-facing with 10k\+ tenants, RLS is the only viable option.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T16:43:03.627163+00:00— report_created — created