Before sharing an AI-built app, keep real data out until you have checked it: separate development from production, turn on and test row-level security with two accounts, keep every secret out of browser code and Git, check permissions on the server, verify each package the AI added, rate-limit forms, use a hosted checkout for payments, run scanners and keep a backup. Most 2025 and 2026 incidents were missing access rules or exposed keys.
Tools you need
The 12 steps
Decide what data the app holds
List every kind of personal data the app stores. If it is health records, financial details, ID documents or anything about children, stop and get a human security review before real users arrive. In India, the Digital Personal Data Protection Act, 2023 allows penalties of up to Rs 250 crore for failing to take reasonable security safeguards, and 'the AI wrote it' is not a defence. This is general information, not legal advice.
Separate development from production
Use one database project for testing and another for real users, and never give an AI agent production credentials. In July 2025 SaaStr's founder reported that a Replit agent deleted his production database during a code freeze that existed only as an instruction, and Replit's CEO called it unacceptable. Rules the agent must never break belong in permissions and separate environments, not in a prompt.
Turn on row-level security for every table
A browser app talks to the database with a public key, so row-level security (RLS) is what decides who can read or change each row. A table without it is open to anyone who has your project URL and public key. In SQL:
alter table notes enable row level security;
create policy "own rows" on notes
for all using (auth.uid() = user_id) with check (auth.uid() = user_id);Repeat for every table. Never let the AI fix an error by disabling RLS.
Test it as an attacker would
Do not trust a green tick from a scanner: researchers noted that scanners check that a policy exists, not that it is correct. Make two accounts and try to read the first user's data as the second. Then try with no sign-in at all:
curl "$SUPABASE_URL/rest/v1/notes?select=*" -H "apikey: $ANON_KEY"The answer must be an empty list or an error, never real rows.
Keep secrets out of browser code and Git
Anything in browser code is public. Only publishable keys may be exposed, and variables with the VITE_ or NEXT_PUBLIC_ prefix are sent to every visitor. A secret or service-role key bypasses RLS and must never reach the browser. Search your repository for keys, add .env* to .gitignore, turn on GitHub secret scanning, and rotate any key that was ever committed or pasted into a public project.
Check permissions on the server, not in the screen
Hiding a button is not security. Every function a browser can call must check who the user is and whether they own the record. Ask your agent to list every server function and API route and what check each one makes, then read the answers yourself.
Validate input on the server
Treat everything from the browser as untrusted. Validate type, length and format on the server, use parameterised queries instead of building SQL from text, and encode output to prevent cross-site scripting. Ask the agent for negative tests: empty values, huge values and script tags.
Verify every package the AI added
AI tools sometimes recommend packages that do not exist, and attackers can register those names. A 2025 study of 576,000 code samples found 19.7% of recommended packages were hallucinated. Look up each new package on npmjs.com, check its age and downloads, pin versions, and run:
npm audit
osv-scanner --lockfile package-lock.jsonAdd rate limits and bot protection
Free plans turn abuse into outages and bills. Put Cloudflare Turnstile on sign-up and contact forms and verify its token on your server. Rate-limit expensive endpoints, add a LIMIT to queries, and set billing alerts or spending caps wherever a service offers them.
Handle payments the safe way
Use a hosted checkout so card numbers never touch your code. Create orders and compute amounts on the server, and verify the payment signature on the server before unlocking anything. Keep secret keys and webhook secrets server-side and stay in test mode until your gateway account is verified.
Run the scanners and read the results
Run your builder's own security scan if it has one, then add Semgrep for insecure code patterns, Dependabot for vulnerable packages and a secret scanner such as TruffleHog or Gitleaks. Scan a running staging copy with OWASP ZAP only if you own it. Fix real findings and note anything you accept.
Prepare for failure
Free database plans may have no automatic backups, so run pg_dump on a schedule. Add Sentry for crashes and UptimeRobot for downtime. Write a three-line leaked-key plan: rotate the key, check the logs, tell affected users. Publish a privacy policy that says what you store.
Make it yours
- Turn the checklist into a GitHub issue template and run it on every new project.
- Audit an open-source vibe-coded app and write up five findings with the fix for each.
- Add the two-account test as an automated Playwright test that runs on every push.
- Add a SECURITY.md that tells people how to report a problem.
Troubleshooting
| Problem | Fix |
|---|---|
| RLS is on but my app shows no data | Row-level security with no policy blocks everything. Add a policy for each action the app needs and test again with a signed-in user. |
| The AI suggested a service key in the front end | Reject it. Put that work in a server function or edge function that reads the key from an environment variable. |
| A scanner says everything passes but I am unsure | Scanners prove a rule exists, not that it is right. Repeat the two-account test and the signed-out request in step 4. |
| I committed a key by mistake | Rotate it immediately at the provider, remove it from the code, and treat the old key as public even after you delete the commit. |
Frequently asked questions
Are vibe-coded apps insecure?
Often, when nobody checks them. Researchers have repeatedly found AI-built apps with missing row-level security, exposed keys and public data. The fixes are well known, which is why this checklist exists.
What is row-level security?
A database feature that decides, row by row, who can read or change data. In a browser-based app it is the main thing protecting one user's data from another.
Can I trust the AI to check its own code for security?
Use it as a reviewer, not the final judge. Ask for a review in a fresh session, then verify the claims with real tests such as the two-account check. Models miss logic and access-control flaws.
Do I need to do this for a student project with no real users?
A lighter version still builds a habit. The moment real users or real personal data arrive, run every step.
Where can I learn more?
Read the OWASP Top 10:2025, Supabase's row-level security guide and Lovable's security documentation, and try the free testing and security tools.
Learn this with mentors
Programmes for builders and engineers with admissions open: live classes, mentors and project work.









