10 min read · September 22, 2026
A worked review of accounts, tenant isolation, secrets, dependencies, data handling, and operations, with the evidence to collect for each check.
You have an app that works. A customer wants to use it with real accounts and real data. The question is no longer whether the demo runs; it is what happens when a user, a tenant, or a dependency behaves differently from the happy path.
Here is how I would review a small AI-built SaaS app. The example is a fictional team dashboard with organizations, file uploads, an AI summary feature, and Stripe billing. Use the free review planner to adapt these checks to your own product.
Write down every route that reads or changes customer data, every role, each background job, and every external service. For one normal user, one admin, and two separate organizations, create test accounts with data you can recognize. Keep production customer data out of the test.
The useful artifact is a short diagram or table: request → route → authorization check → database query → response or side effect. If you cannot trace a sensitive operation through those steps, you do not yet know what to test.
Find where the server establishes identity. Check signup, login, logout, password reset, session expiry, and any service tokens. Try calling a private API route directly without the browser UI. The route should reject an absent or expired session before it reads data.
Evidence: the relevant middleware and route code, an unauthenticated request and response, and a test for expired or revoked credentials. A screenshot of a login page is weak evidence; it says nothing about the API.
With a user from organization A, request a record, export, attachment, and background-job result belonging to organization B. Change IDs in URLs and API bodies. Repeat with a lower-privilege role inside A. Check both reads and writes, including bulk operations and signed download links.
Evidence: queries scoped to the authenticated tenant, server-side policy checks at the operation boundary, denied cross-tenant requests, and regression tests. A UI that hides another tenant's button is not an authorization check. For the fictional dashboard, the decisive test is whether A can download B's generated report by guessing its ID.
Search the built frontend bundle, repository history, logs, error reports, and CI configuration for API keys and database URLs. Check whether service credentials have only the permissions they need and whether test and production environments use different keys. Rotate any credential you find exposed.
Evidence: a redacted secret inventory showing owner, scope, storage location, and rotation method; scans of the shipped bundle and repository; and a test proving a client cannot invoke a privileged integration directly. Do not paste live secrets into a review report or an AI chat.
Trace personal or customer data from collection to storage, logs, backups, exports, deletion, and AI providers. Check upload type and size limits, private storage permissions, retention settings, and who can fetch a generated link. Ask whether the AI summary feature sends complete documents when only a small excerpt is needed.
Evidence: a data-flow map, provider and storage settings, sample redacted logs, an access test for uploaded files, and a demonstrated deletion or retention procedure. Policy text alone cannot establish what the running app does.
List direct and transitive dependencies and their current advisories. Triage alerts by whether the vulnerable code is reachable in your app. Inspect build scripts and third-party actions, then check branch protection, CI results, environment separation, rollback, and backup restore.
Evidence: a dated lockfile and advisory report with triage notes, CI run links, a deployment record, and a recent restore test. “Backups enabled” is a configuration claim; a restore test tells you whether recovery works.
For the example app, try replaying a payment webhook, submitting the same job twice, and consuming a paid AI feature with an unpaid account. Check idempotency, server-side entitlement checks, per-tenant usage caps, retry behavior, and who pays when a request loops.
Evidence: replay tests, a visible entitlement check in server code, usage and cost limits, and logs that connect a job to a tenant without disclosing its data. If the AI feature can call tools, review its tool permissions and prompt-injection boundary separately.
Can you tell which account accessed a record, which deployment changed behavior, and whether an integration failed? Can you act on an alert without reading sensitive payloads in the log? Assign an owner for incidents and test a basic “disable, rotate, restore, notify” sequence.
Evidence: redacted sample events, alert destinations, an incident contact, and the result of a short response exercise. A dashboard with no one watching it does not close the gap.
A good self-review catches missing checks and gives your team a fix list. It may miss a subtle exploit chain, a mistaken assumption shared by the author and reviewer, or a configuration difference in production. Mark each result as observed in code, tested in a running environment, or still unverified. Those are different levels of evidence.
If the app holds sensitive customer data, has several tenants or integrations, or faces an enterprise security review, an independent reviewer is worth considering. Tell them the exact scope and what access is permitted. Our security review investigates the code and configuration, tests agreed paths, and gives you findings tied to evidence. You can start by building your own review plan and bring it to the conversation.