SaaS Security Checklist: Tenant Isolation, Auth, Billing and Data
The security checks specific to multi-tenant software: isolating customers from each other, protecting accounts, handling billing safely and being ready when something goes wrong.
Updated
A SaaS product holds many customers' data in one system, so the worst failure is not a crash. It is one customer seeing another's data. This checklist starts with isolation and works outward to the operational habits that limit damage when something does go wrong.
1. Tenant isolation
- Every table that holds customer data carries a tenant or owner column, and every query filters by it.
- Enforce isolation in the database as well as in application code. Row level security policies mean one forgotten WHERE clause does not become a breach.
- Server-side code that uses an elevated or service-role database key is kept to the minimum, never reachable from the browser, and does its own authorization checks.
- File storage paths and signed URLs are scoped per tenant and expire.
- Background jobs, caches and search indexes carry the tenant context too. Isolation bugs often hide there.
- Write cross-tenant tests: create two tenants and prove that each cannot read or write the other's records through every endpoint.
alter table projects enable row level security;
create policy "members read own projects"
on projects for select
using (owner_id = auth.uid());2. Accounts and sessions
- Use an established identity provider or a vetted library. Do not write your own password hashing or session handling.
- Offer multi-factor authentication, and require it for admins.
- Sessions have sensible lifetimes, cookies are HttpOnly, Secure and SameSite, and logout invalidates the session server-side.
- OAuth callbacks validate state and restrict redirect URLs to your own origins.
- Account recovery cannot be used to take over an account: rate limit it and notify the owner.
3. Authorization
- Roles and permissions are defined in one place and checked on the server for every sensitive action.
- Plan and feature limits are enforced on the server. Hiding a button does not stop a request.
- Admin tooling is separate, logged, and limited to named people.
4. Secrets and configuration
- No secrets in the repository. Use environment variables or a vault, scoped per environment.
- Customer-supplied credentials, such as API keys for integrations, are stored encrypted and never returned in full to the browser or to logs.
- Rotate any secret that has been exposed, and have a documented way to rotate them all.
- Production credentials are not available on developer machines by default.
5. Billing and webhooks
- Verify the signature on every payment-provider webhook before acting on it, and reject events outside a short timestamp window.
- Make webhook handling idempotent. Providers retry, so the same event can arrive more than once.
- Derive the user and plan from data you stored when the checkout was created, not from values the browser sends back.
- Never store card data yourself. Let the payment provider hold it.
- Reconcile entitlements regularly: what the provider says a customer has paid for versus what your database grants.
6. Data protection
- Encrypt data in transit with TLS everywhere, including between services, and at rest through your database or storage provider.
- Collect only the personal data you need, and know where it lives.
- Backups are automated, stored separately, and restored in a test at a regular interval.
- You can export and delete a customer's data on request.
7. Audit logging
- Log security-relevant events: sign-ins, permission changes, data exports, API key creation and admin actions. Record who, what, when and from where.
- Logs never contain secrets or full payloads of sensitive data.
- Audit logs are append-only and retained long enough to investigate an incident. Large customers will ask for access to theirs.
8. Software supply chain and infrastructure
- Dependencies are pinned by lockfile, scanned regularly, and updated on a schedule.
- CI is the only path to production, and secrets in CI are scoped and not exposed to untrusted pull requests.
- Production services expose only the ports and routes they need. Databases are not open to the public internet.
- Security headers and a restrictive Content-Security-Policy are set on the web app.
9. When something goes wrong
- Know who is on call and how they are reached.
- Have a written first-hour plan: contain, preserve logs, rotate credentials, assess which tenants were affected.
- Decide in advance how and when you notify customers, and check the breach-notification rules that apply to the places you operate.
- After every incident, write down what happened and which check would have caught it, and add that check to this list.
This list is engineering guidance, not legal or compliance advice. Frameworks such as SOC 2 require documented policies and independent audit on top of these technical controls.