Tenant isolation verification
Tests tenant boundaries adversarially using comparable data in two workspaces, including indirect relationships and shared infrastructure.
tenant-isolation-verification
Team members using this skill
When is it useful?
Use it before accepting a multi-tenant feature whose ordinary single-workspace tests cannot expose data leakage.
What does it help you do?
- Uses two workspaces with comparable resources and overlapping names.
- Attempts cross-tenant reads, writes and foreign-key injection.
- Checks bulk exports, cache reuse, files and concurrent context handling.
Try asking this
Prove workspace A cannot attach workspace B’s file by guessing its identifier. Use valid A credentials with B's attachment ID in a normal-looking request. Reject the relationship before saving and confirm no copied metadata reveals B's file.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
Tenant Isolation Verification
When to Use
Use during implementation, review, diagnosis, and testing of any multi-tenant feature, endpoint, query, background worker, file handler, or AI tool.
Why Single-Tenant Tests Never Prove Isolation
A test suite that creates Tenant A and asserts Tenant A can read and update its own records proves zero tenant isolation—a query completely missing WHERE tenant_id = ? passes every single-tenant test!
- Mandatory Two-Tenant Rule: Every tenant-scoped feature must be tested with at least two distinct workspaces (
Tenant AandTenant B) seeded with identically shaped resources (and overlapping slugs/names where permitted).
The Adversarial Cross-Tenant Test Matrix
Verify and assert all six isolation vectors in automated tests:
1. Direct IDOR / BOLA Read & Mutation Attempts
- Cross-Tenant Read: Authenticate as a valid member/owner of
Tenant A(with active contexttenantId = A) and requestGET /projects/<projectId_of_Tenant_B>$\rightarrow$ must return404 Not Found(or403), neverTenant B's data. - Cross-Tenant Update / Delete: Authenticate in
Tenant Aand sendPATCHorDELETEtargeting<resourceId_of_Tenant_B>$\rightarrow$ must reject and leaveTenant B's row untouched in the database. - Tenant Header / URL Spoofing: Authenticate as
User 1(member ofTenant A, notTenant B) and passX-Workspace-Id: <Tenant_B>or/w/<Tenant_B>/...$\rightarrow$ must fail membership verification (403/404) before reaching the controller.
2. Cross-Tenant Relational Injection (Confused Deputy Joins)
- Authenticate in
Tenant Aand create or update a record inTenant Awhile passing a foreign key ID (parent_id,category_id,assignee_id,file_id,webhook_id) belonging toTenant Bin the request payload:- Example:
POST /w/tenant-a/tasks { title: "x", projectId: "<project_in_tenant_b>" }. - Verify the server validates that every referenced foreign key belongs to
Tenant A(backed by composite FKs in the DB) and rejects the request.
- Example:
3. List, Search, Aggregation & Export Leakage
- Seed matching records in both
Tenant AandTenant B. - Call list endpoints, search/autocomplete queries, dashboard count/sum aggregations, and CSV/PDF exports as
Tenant A$\rightarrow$ assert the response contains exclusivelyTenant Arecords and zeroTenant Brecords.
4. Missing / Undefined Tenant Context Fail-Closed Check
- Call repository/service methods with
tenantId: undefinedor empty context $\rightarrow$ assert they throw an explicit error rather than falling back to an unfiltered query.
5. Concurrent Interleaved Request Isolation
- Fire concurrent requests (
Promise.all) forTenant AandTenant Bsimultaneously against the same server/worker instance $\rightarrow$ verify zero context bleed across pooled DB connections,AsyncLocalStorage, or shared caches.
6. Revocation & Workspace Switch Verification
- Verify that after removing a user from
Tenant A(or switching active workspace toTenant B), subsequent requests or cached queries forTenant Aare rejected and no staleTenant Adata remains visible.
Included files 1
SKILL.md
