Tenant data leaking across accounts
Background
A Series A B2B SaaS startup ran a multi-tenant platform where each customer's data was supposed to be fully isolated. They were about to launch a self-serve plan and needed confidence in their data model before opening up to a much wider user base.
The finding
During a review of their reporting module, we found a family of queries missing the
tenant_id filter. Tenant isolation was enforced through the ORM in the rest of the
app — but the reporting module used raw SQL for performance, and several of those queries
had been written without the tenant scope.
A user in Company A could retrieve aggregated data that included records from Company B and Company C using a specific report template — including names, job titles, and other user-level attributes that should have been invisible across accounts.
The exposure required an authenticated session and specific knowledge of the report parameters — but any paying customer could have hit it accidentally or intentionally.
CVSS score: 9.1 (Critical) — cross-tenant data exposure affecting all active tenants.
How we fixed it
We identified every raw SQL query in the reporting module and audited each one for tenant
scope. Eleven queries were affected. We provided a fix template — a required
WHERE tenant_id = ? clause with a parameterized binding pattern — and worked through
each affected query with the team.
We also recommended automated tests to assert that no report endpoint returns data belonging to a different tenant than the authenticated session. They implemented these as integration tests that run on every PR to the reporting module.
After remediation, we re-ran our full suite of cross-tenant test cases and confirmed no leakage across any query path.
Outcome
All eleven affected queries were fixed within three weeks. A review of the full codebase found no additional instances of raw SQL missing tenant scope. No evidence of unauthorized cross-tenant access was found in the logs. The team introduced a default tenant-isolation middleware that wraps all queries, eliminating the class of issue going forward.
All client details are anonymized. Sector and finding type are accurate.
Have a similar problem?
Tell us about your scope. We'll respond within two business days.