Security questionnaires ask whether a vendor is multi-tenant. Almost every SaaS product is, so the answer is yes and the question was wasted. The question that produces information is where the tenant boundary is enforced, because that single design decision determines whether a cross-tenant leak requires a deliberate attack or a distracted afternoon.
What follows is a question list you can send to a vendor, with the reason each question matters. The reasons are the useful part: they tell you what a bad answer costs you.
Question 1: where is the tenant identifier applied?
There are three honest answers, and they are not equally strong.
In application code, per query. Every query is written with a tenant predicate by a developer who remembered. This works until someone does not remember. It is the most common architecture in SaaS and the weakest, because correctness depends on unbounded future discipline.
In the data layer. Scoping is applied by the layer that builds queries, not by the developer writing them, so a query that omits the tenant cannot be constructed on that path. This is strong when it is genuinely inescapable and theatre when there is a raw-query escape hatch that half the codebase uses.
In the database engine. Postgres row-level security policies enforce scoping below the application. Strongest, and rarer, because it requires session-variable discipline in connection pooling.
Ask which one, then ask the follow-up that matters: what percentage of endpoints bypass it, and what is on the other side of the bypass?
Question 2: what does the schema look like, and what is not tenant-scoped?
| Topology | Leak requires | Real operational cost |
|---|---|---|
| Shared tables, tenant column | One missing predicate on one query path | Lowest; one migration set, one backup |
| Schema per tenant | A connection routed to the wrong schema | Migration fan-out across every schema |
| Database per tenant | Connection-string or routing error | Highest; per-tenant patching, backup, monitoring |
A vendor who answers “shared tables” is not giving you a bad answer. A vendor who cannot tell you which tables are not tenant-scoped is. Every real system has some: reference data, platform configuration, the tenant registry itself. The ones worth worrying about are the tables that hold customer business data and somehow escaped the pattern.
Oneop’s security page publishes this as a count rather than a posture: 275 of 329 tables carry a tenant_id column, and the remaining 54 are itemised. 28 belong to the internal operator console, which is a separate application that ships disabled. 18 are child records inheriting the boundary through a foreign key to a tenant-scoped parent. 4 hold global reference data such as tax jurisdictions and VAT rates. 3 are a shared directory of publicly published company information. One is the tenant registry. That enumeration is the answer you want from any vendor, whatever their numbers turn out to be.
Question 3: can a caller choose their own tenant?
Registration and invitation endpoints are the interesting attack surface, because they accept input before a session exists. If a signup request body containing a tenantId is honoured, an attacker joins your workspace rather than creating their own. The same applies to role: if the request body can set role: admin, the boundary was never the problem.
The correct behaviour is that public registration always provisions a new tenant, a caller-supplied tenant identifier is rejected outright rather than ignored, and the initial role is hardcoded rather than read from the request.
A related question worth asking: do update endpoints run a mass-assignment guard? If a PATCH copies arbitrary request fields onto a record, then fields you never exposed in the UI, including ownership fields, are writable by anyone who can guess a column name.
Question 4: the failure case to ask about directly
Ask what happened the last time a query shipped without a tenant predicate, and what stopped it.
Here is the shape of the incident. A developer adds an export endpoint for a new report. The list endpoint beside it uses a scoped query builder; the export uses a raw SQL string for performance, because the report joins four tables and the builder generated a slow plan. The raw query filters by date range and status, which was the whole feature request, and nobody notices that the tenant predicate was in the builder rather than in the requirement.
The endpoint passes review because the reviewer checks the SQL for correctness against the feature, not against an invariant nobody wrote down. It passes tests because the test fixture has one tenant. It ships. Three months later a customer opens a CSV containing another customer’s contact list, and the disclosure obligation is triggered by an export rather than a screen, which means the data has already left both buildings.
Every element of that story is ordinary. That is the argument for enforcement below the developer: the mistake is not exotic, so the control cannot rely on the mistake being rare.
Reporting systems deserve the same question, because a report builder is a query builder with a user interface on it. In Oneop’s reporting engine, the workspace filter is not part of the report configuration at all; the engine builds it from the dataset definition, applies it to the base table on every query, and applies it again to each joined table rather than trusting the relationship to have carried it. A report definition names dimension, measure and filter keys from a server-owned catalogue, so there is no configuration that can widen or remove the predicate.
Question 5: how are backups and restores scoped?
This is the question that separates vendors who have practised recovery from vendors who have configured it.
Ask: can you restore one tenant to a point in time without rolling back every other tenant? If the answer is no, then recovery from your own accidental deletion competes with everyone else’s uptime, and the practical resolution is that it will not happen.
Ask where backups live, how they are encrypted, and whether the key is held somewhere the compromised server cannot reach. A backup encrypted with a key stored beside it protects against disk failure and not against an intruder. Ask about every copy, including the infrastructure-level ones: host snapshots taken by the hosting provider are a second copy of your data under a different retention policy, and a vendor who has not mentioned them has not finished the inventory.
Question 6: what limits one tenant’s consumption?
Data isolation and performance isolation are different properties. One tenant running an unbounded export, a runaway automation loop or an integration retrying in a tight cycle can degrade everyone on shared infrastructure.
The answers that indicate thought are numeric: per-tenant rate limits on public endpoints, a row ceiling on report execution with truncation reported rather than hidden, a cap on concurrent jobs. Oneop’s reporting engine caps at 5,000 rows per run and marks a capped result as capped, which is a limit that is also a correctness property.
Question 7: how is staff access constrained?
Somebody at the vendor can reach the database. Pretending otherwise is the unreliable answer. The useful questions are whether staff access to customer accounts runs through a separate application with its own login and mandatory two-factor, whether sessions are time-boxed, whether they can be revoked mid-session, and which actions are hard-blocked.
Then ask the one people forget: can the access log be modified or deleted by the people it records? An audit log with an update route is a document, not a record.
Question 8: how is an incident affecting one tenant contained?
Containment is mostly about blast radius decided in advance. Shared session-signing secrets across different classes of user are a good probe, because they are a common shortcut: if the staff application, an admin console and a customer-facing portal sign sessions with the same secret, a cookie minted in one realm can be replayed in another.
Ask whether separation is enforced at boot or by deployment convention. Oneop runs three session principals with three cookie names and three signing secrets, and production start throws unless all three are distinct, which turns a configuration error into a failed deploy rather than a latent vulnerability.
How to read the answers
Precision is the signal. A vendor who answers with counts, enforcement points and named failure behaviours is describing a system they have examined. A vendor who answers with adjectives and a certificate number has told you about their audit, which is a different thing from their architecture. For the equivalent question set applied to AI capability claims, see what is an AI-first customer platform; for why placement inside the boundary changes what software can be trusted to do, why your AI agent should live inside your system of record covers the argument. Pair this list with how Oneop governs AI if agents will touch the same data.