Build1 publisher3 min readPublished
A flat tenant_id forces the three workarounds that ship cross-tenant leaks
A checklist written by someone who sells generated multi-tenant backends dates the tenant model and the source of tenant identity to day one, and the database isolation argument to the first paying customer. The author then runs the test on their own product.
The Engineer · Build desk

What happened
- A dev.to post frames multi-tenant SaaS as seven decisions, six of which it says need answering now, with the one teams argue about first placed last.
- It ties a single flat tenant_id to three specific workarounds: a fake second account for a customer with two departments, an application-level join for a reseller, and a session hack for a user who belongs to two tenants.
- It names the provenance of tenant identity, not the storage tier, as the decision that produces the most real vulnerabilities, with a caller-supplied org_id in the request body singled out as the version that ships breaches.
- The author, who discloses working on Supero, runs the post's own leak test against Supero and lists three ways around its boundary that require no developer mistake.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure If tenant scope arrives in a request field, both middleware and row-level security enforce a scope the caller picked, so a team can pass an isolation review and still hand out other tenants' rows.
- cost Each database-tier option puts its cost on whoever operates the system: RLS expertise, schema migrations run as a project, or analytics and connection pooling that get hard once tenant counts reach the hundreds.
- decision Sequencing the list this way lets a small team close the identity hole with a grep and a written rule now, and postpone the storage-tier commitment until there is a customer paying for it.
- precedent A vendor publishing its own bypass list sets a standard buyers can hold the next one to: name the exemptions, or explain what stops a new call site from skipping the producer.
Three of the decisions the post spells out share a deadline of day one: what a tenant is, how deep the hierarchy goes, and where tenant identity comes from [4][5][8]. Isolation enforcement is the one with a later date, the first paying customer [15]. That deferral is priced. Moving later means "auditing every query you have ever written, and you will not find them all", the post's author wrote [15]. The hierarchy works the same way: adding a level later means rewriting every query you have, so the advice is to pick organisation -> workspace -> user and use one level of it for a year [5].
The identity decision is the one the post calls the most productive source of real vulnerabilities [6]. Tenant scope can come from a subdomain, a signed JWT claim, a session lookup, or an org_id in the request body that the caller supplies [6]. "An isolation layer that cannot omit tenant scope is worth nothing if the scope it cannot omit was chosen by the attacker," the author wrote. The same goes for row-level security keyed on a claim the API populates from user input, the author added [7]. So the storage tier does not rescue you here. The rule offered is that identity comes from exactly one place, server-derived, with no request field able to override it. The follow-up advice is to grep for the places that do it differently, because there will be some [8]. In my view this is the cheapest item to act on this week, because it is greppable and the answer is binary.
The isolation options have different costs. The application-level WHERE clause is fast to build and fails the first time one developer on one endpoint forgets, silently, returning 200 with too many rows [10]. Database enforcement is stronger because forgetting stops being possible. Each form costs the operator work: RLS is its own skill and can be subtly wrong, schema-per-tenant turns migrations into an operational project, and database-per-tenant makes cross-tenant analytics and connection pooling hard at a few hundred tenants [11]. The shared middleware producer writes the scope once instead of at forty call sites. That removes the per-endpoint mistake, the post says, but it does not make the boundary unforgettable the way a database refusing a query does [13].
Then the author applies the leak test to Supero and reports it does not pass cleanly. Admin roles have documented exemptions. A user left in the platform's default-tenant gets project-wide read, and a request arriving with no session context returns allow, a branch the post says is unreachable today only because authentication runs first [17]. The score given is "a developer cannot leak by forgetting, and can leak by being provisioned wrong" [18]. The post also tells readers to ask any vendor selling this design, "us included", whether the producer has bypass branches and what stops a new call site from skipping it entirely [14].
This is one practitioner's checklist with a vendor disclosure attached [19]. It cites no incident data for the claim that the fake-account, application-join and session-hack workarounds are how leaks actually ship [3]. What transfers regardless of stack is the test, and it costs an afternoon. Ask a developer to write an endpoint that leaks across tenants. If nothing stops them but their own care, their care is your isolation model [16]. Note also that the post refuses to treat database-per-tenant as a separate decision at all, calling it the physical tier of the same isolation choice [12].
What to watch
- Whether Supero removes the no-session-context allow branch. The post says it is unreachable only because authentication runs first.
- Whether any vendor selling middleware tenant scoping answers the two questions in writing: bypass branches, and what stops a new call site skipping the producer.
- Published post-mortems that name the tenant model as the root cause of a cross-tenant leak.