---
name: audit-app-security
description: Audits a web app for the security holes AI-written code most often ships - leaked secrets, missing auth checks, open database rules, injection, unsafe uploads, weak headers and vulnerable packages - and fixes them in priority order. Use when the user asks for a security review or audit, worries their vibe-coded app is hackable, or wants to harden an app before going live.
license: CC-BY-4.0
metadata:
  category: backend
  tags: "security,auth,launch,quality"
  author: johnny-bravo
  version: "1.0"
  updated: "2026-10-31"
  status: published
  aliases: "security-audit,security-hardening,security-review"
---

# Audit app security

AI coding tools build features fast, but often skip the checks that stop strangers reading other people's data. This audit walks the usual holes from most to least dangerous. Fix each one, then move on.

## When to use
- Before launching an app that has logins, payments or user data.
- You built it with AI help and are not sure what it left open.
- Someone reported a bug that looks like a security problem.

## Steps
1. **Map the app.** List every page, API route, server action, webhook and database table. Note which ones need a logged-in user.
2. **Hunt for leaked secrets.** Search the code and git history for API keys, tokens and passwords. Run a scanner such as `gitleaks detect` or `trufflehog git file://.`. Rotate any key that was ever committed; deleting it is not enough.
3. **Check what the browser sees.** Variables starting with `NEXT_PUBLIC_`, `VITE_` or `EXPO_PUBLIC_` ship to every visitor. Only public keys belong there.
4. **Check auth on every server route.** Each route must check who the user is on the server. Hiding a button in the UI is not protection.
5. **Check ownership.** Change an id in a URL or request to another user's id. If you see their data, add an "owned by this user" check. This bug (IDOR) is the most common one.
6. **Lock the database.** On Supabase or Firebase, turn on row level security or security rules for every table, then test them logged out and as a second user.
7. **Stop injection.** Use parameterised queries or your ORM, never string-built SQL. Never pass user input into shell commands or `eval`. Escape output and avoid `dangerouslySetInnerHTML` with user content.
8. **Check uploads and webhooks.** Limit file type and size, and store uploads outside your code folder. Verify webhook signatures, for example Stripe's `constructEvent`.
9. **Add protective headers and limits.** Set HTTPS-only cookies (`HttpOnly`, `Secure`, `SameSite`), a Content Security Policy, and a strict CORS list. Rate limit logins, sign-ups and any costly API.
10. **Check packages.** Run `npm audit` (or `pnpm audit`, `pip-audit`) and update anything rated high or critical.
11. **Write up findings** as a table: issue, where, risk (high, medium, low), fix, done. Fix the high-risk rows first, then re-test each fix.

## Gotchas
- Client-side checks can be skipped by anyone. Every real check runs on the server.
- Error messages and stack traces can leak table names or keys. Show users a plain message and log the details.
- A new admin route or table added later needs the same checks. Re-run steps 4-6 after big changes.
- For AI chatbots, also see `add-chatbot-guardrails-and-rate-limits` for spend caps and prompt-injection defence.

## Safety
- Only test apps and accounts you own or have written permission to test.
- Test with throwaway accounts and a staging copy of the data, not real customers.
- Never paste real secrets or customer data into chat. Use placeholders.

## Works with other stacks
Works with any stack: Next.js, Express, Django, Rails, Supabase, Firebase or similar. If you use a different scanner or audit tool, the order of checks stays the same.

## Done when
- No secrets in the code, history or browser bundle, and any leaked key has been rotated.
- Every server route checks login and ownership, and a second test user cannot see the first user's data.
- `npm audit` (or the equivalent) shows no high or critical issues.

## Example prompt
"I built my app with Cursor and launch next week. Check it for security holes and fix the worst ones."
