Install
$ agentstack add skill-05-deepak-patidar-claude-skills-saas-multi-tenancy ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
SaaS Multi-Tenancy
In a multi-tenant system, the worst bug class isn't downtime — it's tenant A seeing tenant B's data. One leaked invoice ends the customer relationship and possibly the company. Design so that isolation failures are structurally impossible, not just carefully avoided, because "carefully" doesn't survive the 400th endpoint.
Choosing the isolation model (decide once, explicitly)
- Shared schema +
tenant_idcolumn — the default. Cheapest to operate, easiest to migrate, scales to thousands of tenants. Requires the discipline below. - Schema-per-tenant / database-per-tenant — buy isolation with operational pain (N× migrations, connection management, cost). Justified by: hard compliance walls, wildly divergent tenant sizes, or contractual "your data is physically separate". Don't drift here for comfort.
- Hybrid (big tenants carved out) is legitimate — but only after the shared model measurably strains.
The rest of this skill assumes shared-schema, where the discipline matters most.
Gate 1: Scoping that fails CLOSED
The core principle: a forgotten WHERE clause must return nothing, not everything.
- Two layers, always: application-level scoping (every query goes through a tenant-scoped session/repository that injects
tenant_id— never hand-written per query) AND database-level enforcement (Postgres RLS withFORCE, policies keyed off a per-request setting, app connecting as a role that cannot bypass RLS — superusers silently bypass it; verify the role, and boot-guard against misconfiguration). tenant_id NOT NULLon every tenant table + FK to the tenants table + composite indexes leading with it (database-design). New tenant-scoped table = added to the RLS/policy list in the same migration, enforced by convention and a test that scans the schema for unpoliced tables.- The tenant comes from the authenticated principal, never from the request — no
?account_id=params, no tenant in the POST body, no trusting a JWT claim you didn't issue (threat-model-security Gate 1).
Gate 2: Context propagation — where leaks actually happen
Request handlers are the easy part. Cross-tenant leaks live in the places that don't have a request:
- Background jobs: every enqueued job carries its
tenant_idexplicitly, and the worker re-establishes tenant context before touching data. A worker processing a loop of tenants must reset context per iteration — context bleeding between loop iterations is the classic leak. - Caches: every cache key of tenant-scoped data includes the tenant (system-design). Query caches cleared on login/logout — stale cross-account data in an SPA is this bug wearing a frontend costume.
- Scheduled/cron jobs, exports, report generators, search indexes, LLM/RAG retrieval (ai-engineering): each is a query path; each gets the same scoping audit as an endpoint.
- Logs and error trackers: tag entries with tenant (great for debugging) but treat aggregated views as cross-tenant data needing admin-level access.
Gate 3: The two-tenant test — the cheapest breach prevention that exists
In your test suite, permanently: seed tenant A and tenant B, then as A's user attempt to read, update, delete, and list B's objects on every resource type — expecting 404/empty, never data. Add the list-endpoint case explicitly (unscoped lists leak in bulk). Run it in CI; every new resource joins it. Before any launch, run it live against production-like data (release-readiness Gate 2). This one fixture catches the bug class that code review misses.
Gate 4: Tenant lifecycle is a feature set, not an afterthought
Design these before the first real customer, because retrofitting them is surgery:
- Provisioning: idempotent tenant creation (seed data, defaults, numbering sequences) — one function, tested.
- Suspension (unpaid/abusive): a
blocked/suspendedflag checked at auth time, gating the whole app — data preserved, access stopped, reversible. - Export: a tenant can get their data out (their invoices, parties, ledgers) in a usable format. Contractually expected; also your data-privacy-compliance obligation.
- Purge: hard deletion of a departed tenant — everywhere: rows, files/objects, search indexes, caches, backups-policy documented. An orphaned tenant's data is pure liability. Purge is destructive: confirm, audit, and stage it (soft-delete window → hard purge).
Gate 5: Tenants are not the same size — plan for the whale
- Noisy neighbor: per-tenant rate limits on expensive endpoints, caps/pagination on unbounded queries (that one tenant with 500k products will find your missing LIMIT), and background-job queues that can't be monopolized by one tenant's bulk import (fair scheduling or per-tenant concurrency caps).
- Observe per-tenant: your metrics need a tenant dimension on the hot paths — "the API is slow" vs "tenant 4 is running 80% of load" are different incidents (observability-readiness).
- Per-tenant configuration (features, limits, branding) lives in a tenants/settings table read at runtime — never in code branches naming specific customers.
Cross-tenant admin operations
Your own admin/support panel is deliberately cross-tenant — which makes it the highest-privilege attack surface you own: separate principal type and stronger auth, every cross-tenant read/write written to an append-only audit log (who viewed which tenant's what, when), and impersonation (log-in-as-tenant), if built, is time-boxed, visibly flagged in the UI, and audited. Support convenience is how breaches get built with good intentions.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: 05-deepak-patidar
- Source: 05-deepak-patidar/claude-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.