This is the list we run against every app we audit. It is published in advance on purpose:
ask anyone else quoting you for this work to show you theirs.
Data & access
The main category, and the one where a single mistake exposes the most data at once. Written in Postgres terms because most of these apps use Supabase, but the question is the same wherever the data lives — a SQLite file in a container, a self-hosted database, Firebase, or an API you wrote by hand: who can read this row, and what stops them?
A1
Row-level rules protect every table, not just the app's own code
Postgres and Supabase: RLS enabled on every table in the public schema. SQLite, MySQL, Mongo or a hand-written API: the same check enforced in the one place every request passes through.
CRITICAL
A2
Every table with row-level security switched on actually has a policy
RLS on with no policy denies everything, which is why it tends to get switched straight back off.
HIGH
A3
No rule grants access to everybody
USING (true) in Postgres, a route with no owner check elsewhere: either way, any signed-in user reads every row.
CRITICAL
A4
Rules cover writes as well as reads
Policies on all four operations, not only SELECT — and the delete path checked, not assumed.
CRITICAL
A5
Writes are checked against the rule they are meant to satisfy
WITH CHECK on INSERT and UPDATE policies, so a row cannot be written into somebody else's account.
CRITICAL
A6
No access decision rests on data the user can edit
Supabase user_metadata, a claim the client can set, a role column in the user's own row.
CRITICAL
A7
Multi-tenant isolation filters by tenant, not only by user
CRITICAL
A8
No admin-level key or connection string reaches the browser
A Supabase service_role key, Firebase admin credentials, or a raw database URL in the front-end bundle.
CRITICAL
A9
File storage: only the buckets that should be public are
Supabase Storage, an S3 bucket, or an uploads directory served straight off the web root.
CRITICAL
A10
Functions that run with elevated rights are safe
Postgres SECURITY DEFINER, stored procedures, admin-only RPC endpoints.
HIGH
A11
Views and API routes do not go around the row rules
HIGH
A12
The database is not reachable from the internet on its own port
A container publishing 5432, 3306, 27017 or 6379, a database file sitting under the web root, or an admin console left open — very often still on the credentials it shipped with.
CRITICAL
A13
Cascading deletes do not remove unrelated data
MEDIUM
Secrets
Any finding here means the key is treated as compromised. Removing it from the code is not enough — it has to be rotated.
B1
No secret keys in the client bundle
CRITICAL
B2
Source maps are not published to production
HIGH
B3
Service files are not reachable (.env, .git/config, config.json, backup.sql, the database file itself)
CRITICAL
B4
No keys anywhere in the git history
HIGH
B5
Keys were rotated after a finding, not just removed
CRITICAL
Authentication & authorisation
Sign-in works on the first try, so nobody checks it again. Authorisation is what actually fails.
C1
Email confirmation is switched on
HIGH
C2
Roles are checked on the server, not only in the UI
CRITICAL
C3
OAuth redirect URIs are on an allowlist
CRITICAL
C4
Sessions expire and refresh tokens rotate
MEDIUM
C5
Password reset does not reveal whether an account exists
MEDIUM
C6
Password policy and brute-force protection
HIGH
Resilience
The category nobody else checks, and the one that most often ends the business rather than just the feature.
D1
Automatic backups are enabled
CRITICAL
D2
A restore has actually been tested
CRITICAL
D3
Error logging works
HIGH
D4
Alerts reach a channel somebody reads
HIGH
D5
Payment failures are handled
CRITICAL
D6
Webhooks are idempotent
CRITICAL
D7
The app degrades rather than dies when an external API is down
MEDIUM
D8
Timeouts and retries are set explicitly
MEDIUM
Load & cost
Works in a demo, dies on launch day — and the bill arrives either way.
E1
No N+1 query patterns
MEDIUM
E2
Indexes on foreign keys and on columns used by RLS policies
MEDIUM
E3
Rate limiting on public endpoints
HIGH
E4
File upload limits on size and type
MEDIUM
E5
A cost projection at ten times current usage
MEDIUM
Legal & platform
Cheap to fix before launch, expensive after.
F1
A privacy policy that matches what is actually collected
HIGH
F2
A cookie banner where one is required
MEDIUM
F3
No App Store rejection risk from runtime code generation
HIGH
F4
Security headers: CSP, HSTS, X-Frame-Options, X-Content-Type-Options, CORS
MEDIUM
Want this run against your app?
The first check is free and the audit price is on the page — no sales call required.