The question from a security questionnaire
A larger prospect sends a security questionnaire. One question asks how you ensure customer data is isolated. The honest answer is that every query includes the customer ID, and you think they all do. Or a developer mentions in passing that an export endpoint did not check the account, and it was fixed, and you start wondering what else might be like that.
Nothing bad has happened, as far as you know. But you cannot prove it, and you are not fully confident it could not.
Why isolation is fragile in most apps
Most SaaS products keep all customers in one database, with a column on each table saying which customer the row belongs to. That is a sound design. The weakness is how it is enforced. If isolation relies on each developer adding the right filter to each query, it holds only as long as nobody forgets.
- New endpoints written in a hurry, missing the customer filter.
- IDs in URLs that can be changed to another customer's record.
- Background jobs and exports that run outside the normal request checks.
- File storage where one customer's files sit next to another's under guessable paths.
- Caches keyed without the customer, serving one tenant's data to another.
- Admin and support tools that bypass the checks altogether.
What the uncertainty costs
| Risk | Consequence |
|---|---|
| A cross-tenant leak | Loss of trust, possible regulatory reporting duties |
| Failed security reviews | Larger deals stall or are lost |
| Slow questionnaires | Sales cycles drag while answers are worked out |
| Developer anxiety | Every new feature carries the same risk |
A data leak between customers is one of the worst things that can happen to a B2B SaaS product, because customers chose you partly on trust. Where personal data is involved, it may also carry legal obligations, which is something to take proper advice on.
How we check and harden data isolation
- Map every data path. Endpoints, background jobs, exports, file storage, caches, search indexes, analytics and admin tools, listing how each one decides which customer it serves.
- Test for cross-tenant access. With two test customers, we try to reach one's data while logged in as the other, through every path, including changing IDs in requests.
- Fix what we find, starting with anything exploitable, and report it to you clearly.
- Enforce isolation lower down. Depending on your stack, that means PostgreSQL row-level security, a data access layer that applies the customer scope automatically, or ORM-level scoping that cannot be skipped by accident.
- Scope files and caches. Storage paths and signed URLs per customer, and cache keys that always include the tenant.
- Add automated tests. Cross-tenant tests run on every release, so a new endpoint that leaks fails the build before it reaches production.
- Log access. Admin and support access to customer data is logged, so you can answer who saw what.
- Document it. A clear description of how isolation works, useful for security questionnaires and for new developers.
Where a customer needs stronger separation, such as a dedicated database, we can design for that too, but most products do not need it for every customer.
Confidence you can explain
The written description of how isolation works also changes how new features are built. Developers know which layer enforces the customer scope and do not have to reinvent it for each endpoint, and reviewers have a clear rule to check against.
You can answer the questionnaire with a description of how isolation is enforced, not a hope. Developers can add features without re-checking every query by hand, because the lower layer catches mistakes. Tests fail loudly if something regresses. And if a customer asks who accessed their data, there is a log to show them.
Should you check your isolation?
- Isolation depends on each query including the customer ID.
- You have not tested for cross-tenant access deliberately.
- Record IDs in your URLs are sequential numbers.
- Exports, jobs or admin tools run outside the normal checks.
- Security questionnaires are becoming hard to answer honestly.