Guide
A pre-launch security checklist for AI-built apps
You built it with Cursor, Lovable, Bolt, Replit or Claude Code, and it works. Before you put real users and real data on it, spend a day on the checks below. They are in the order we check them, starting with the ones that are cheapest to verify and most damaging to miss. Each takes minutes, and none needs a security background.
For context: Symbiotic Security scanned 1,072 Supabase-backed apps built with AI tools in 2026 and reported at least one issue in 98% of them, though much of that is minor, like missing headers. The more useful figures are that 16% had a critical flaw and 172 apps allowed unauthenticated data deletion. This is vendor research, not an audit of your app, but it shows where the serious problems cluster.
1. Secrets
Search the code, the built output and the git history.
# built output: anything that looks like a secret key?
grep -rE "sk_(live|test)_|service_role|BEGIN (RSA|PRIVATE)" dist/ .next/static 2>/dev/null
# history: use an open-source scanner such as gitleaks
gitleaks detect --source . --log-opts="--all"
Rules: variables with public prefixes (NEXT_PUBLIC_, VITE_, REACT_APP_) end up in the browser, so they hold public values only. A key that was ever public must be rotated, not just deleted.
2. Authentication
- Sessions expire, and logout invalidates them on the server.
- Password reset links are single-use and expire.
- Rate-limit login and reset endpoints.
- No default or test accounts left in production data.
3. Authorization on every route
Write down, for each API route, who may call it. Then test with two ordinary accounts: account B must not read or change account A's data. Test logged out too. A minimal check:
# should return 401, not data
curl -i https://your-app.example/api/orders
# as user B, using user A's order id: should return 404 or 403
curl -i -H "Authorization: Bearer $TOKEN_B" https://your-app.example/api/orders/$ORDER_A
4. Database rules
If you use Supabase or a similar backend-as-a-service, check that row-level security is enabled on every table in the exposed schema.
select schemaname, tablename, rowsecurity
from pg_tables
where schemaname = 'public';
Any row with rowsecurity = false needs attention. Then confirm that every table has policies for select, insert, update and delete as needed. Keep the service-role key on the server only.
5. Input handling
- Use parameterized queries; never build SQL from strings.
- Validate request bodies with a schema and allow only named fields (this stops mass assignment such as a user sending
role: "admin"). - Escape output; avoid
dangerouslySetInnerHTMLandeval-style code with user input. - File uploads: check type and size, store outside the web root or in a bucket with private access.
6. API and configuration exposure
- Remove debug routes, admin panels without auth, and public API docs for internal endpoints.
- Set CORS to your actual origins, not
*with credentials. - Turn off verbose errors in production; stack traces leak structure.
- Add basic security headers:
Content-Security-Policy,X-Content-Type-Options,Strict-Transport-Security.
7. Dependencies
AI tools sometimes add packages that are abandoned or do not exist under that exact name.
npm audit --omit=dev
npm ls --all | head
Check that each dependency is one you recognise, actively maintained and spelled correctly. Pin versions with a lockfile and commit it.
8. Anything with an LLM or an agent
If the app calls a model or gives it tools:
- Treat any text a user or third party can write (tickets, emails, web pages, documents) as untrusted input to the agent.
- Give tools the smallest permissions that work; use read-only credentials by default.
- Require human confirmation before actions that send data out or change permissions.
- Do not put secrets in system prompts, because a model can be talked into repeating them.
- Log tool calls with the input that triggered them.
- Inventory every MCP server in use: who wrote it, which version, which credential it holds.
Public examples include prompt injection against agents connected to GitHub and Supabase tooling, and malicious MCP packages (UpGuard's list of MCP incidents). The OWASP Top 10 for LLM applications is a good reference for the categories.
9. Logging, backups, and recovery
- You can answer "who did what, and when" for sign-ins and for changes to important data.
- Backups exist and you have restored one at least once.
- You know how to rotate every key within an hour. Write the list of keys down now.
10. Set up a guard that stays on
A checklist run once decays. Add to CI: a secrets scan, a dependency audit, and a static analysis step, and make them block merges. Then every future AI-generated change is checked before it merges, which is the point of a review step.
# .github/workflows/security.yml (minimal example)
name: security
on: [pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- run: npm audit --omit=dev --audit-level=high
- uses: gitleaks/gitleaks-action@v2
How to use this list
Mark each item pass, fail or not applicable, and write down the evidence for the passes: the command you ran and what it returned. Fix failures before launch, starting with secrets, authorization and database rules.
Want a senior engineer to run this for you?
The Launch Security Check covers secrets, authentication, authorization, database rules, API exposure and dependencies for one app, from US$790 fixed. Every finding is confirmed by a senior engineer and comes with a fix. It is a review of code and configuration with the access you grant, not a penetration test or a certification.
Sources
- Symbiotic Security, "We scanned 1,072 vibe-coded apps", 2 June 2026 (symbioticsec.ai/blog)
- UpGuard, MCP security incidents, 1 July 2026 (upguard.com/blog)
- OWASP GenAI Security Project, Top 10 for LLM Applications (genai.owasp.org)
- Code samples and checklist: written by Proofmerge for this guide.