Vibe Coded App Security Checklist: 28 Checks From Real Audits

Vibe Coded App Security Checklist: 28 Checks From Real Audits

You built an app with Lovable, Bolt, Cursor, Replit or v0. It works. People are signing up. Somewhere in the back of your mind is a question you have not had time to answer: is it safe?

The research says probably not, out of the box. Veracode tested more than 100 AI models and found they introduced a known security flaw in 45% of coding tasks. Researchers at Escape scanned publicly deployed vibe-coded apps and found more than 400 leaked secrets, including API keys and payment keys. In 2025, 170 of 1,645 Lovable apps scanned were exposing database records through missing access rules, which became CVE-2025-48757.

Most checklists for this stop at Supabase settings. This one goes further, because the worst problems we find in audits are not settings at all. They are logic flaws that no scanner can see: an endpoint that hands any logged-in user someone else's records, or a sign-up form that lets a user make themselves an admin.

The 28 checks below come from two real audits of AI-built apps in 2026, plus the published research. Each one says what to look for, how to test it on your own app, and whether a scanner will catch it or you need a person to look.

How to use this checklist

Work through it in order. The sections are sorted by how much damage a miss can do, so data access comes first and production housekeeping comes last.

Each check is tagged:

  • Scanner: an automated tool (Supabase Security Advisor, npm audit, a secret scanner) will usually find it.
  • Person: a scanner will not find it. Someone has to read the code or try to break the app.

Only test against your own app and your own accounts. Several of these tests are, in effect, small attacks, and running them against someone else's system is illegal in most countries.

1. Data access: who can read and change what

This section is where real customer data leaks. If you only have an hour, spend it here.

Check 1: Row-level security is on for every table (Scanner)

If your app uses Supabase, the browser talks to your database directly with a public key. Row-level security (RLS) policies are the only thing deciding which rows each caller can see. A table with RLS switched off is readable by anyone who opens your site's JavaScript.

Test: in the Supabase dashboard, open the Security Advisor and fix every RLS warning. Then run this in the SQL editor to list unprotected tables:

select tablename from pg_tables
where schemaname = 'public' and not rowsecurity;

Fix: enable RLS on each table, then add policies. RLS with no policies blocks everything, which is safe but will break the app until the policies exist.

Check 2: Policies check ownership, not just "logged in" (Scanner, partly)

A policy that says using (true), or only checks that the caller is authenticated, is barely better than no policy. Every signed-in user can read every row.

Test: create two test accounts. Sign in as the first, create some data, then sign in as the second and try to load it.

Fix: scope rows to their owner, for example using ((select auth.uid()) = user_id), with a matching with check for inserts and updates. Never base access on user metadata, because users can edit their own.

Check 3: Every endpoint checks that the caller owns the record (Person)

This is the most damaging flaw we find, and scanners miss it completely. An API route reads an ID from the URL, such as /conversations/41, and returns that record without asking whether the caller is allowed to see it.

In a B2B marketplace prototype built on Replit that we audited in August 2026, more than 12 endpoints worked this way. Any logged-in business could read any other business's private chats and see every competitor's quoted price on a request for quotation. IDs were sequential numbers, so collecting the whole platform's data would have taken a simple loop.

Test: with your two test accounts, copy the ID of a record that belongs to account A, sign in as account B, and request it directly. Do the same for edit and delete.

Fix: every handler that takes an ID must check ownership on the server before doing anything, ideally in one shared function so no route can forget it.

Check 4: Requests cannot set fields they should not (Person)

AI-generated handlers often save whatever the request body contains, with code like .set({ ...req.body }). That lets a user send fields the form never showed them.

In the same audit, five routes did this. A business could mark itself as verified, a badge only an administrator was supposed to grant after checking documents, by adding one field to an ordinary profile update.

Test: search the code for ...req.body, ...body and similar spreads into database writes. For each one, ask what happens if someone adds isAdmin, role, isVerified or userId to the request.

Fix: validate every request against a schema that lists only the fields the user may change, and drop everything else.

Check 5: Uploaded files are private (Scanner, partly)

Profile photos can be public. Invoices, ID documents and chat attachments cannot.

In the marketplace audit, the route serving private files had its access check commented out, with a note to switch it on later. Business registration documents would have been downloadable by anyone with the link.

Test: upload a private file as account A, copy its URL, and open it in a private browser window with no login.

Fix: make buckets private, serve files through short-lived signed URLs, and apply the same ownership rule as Check 3.

Check 6: Firebase rules are not in test mode (Scanner)

If your app uses Firebase, look for allow read, write: if true; or a test-mode rule with an expiry date. Both leave the whole database open.

Fix: require request.auth != null and match request.auth.uid to the document owner.

2. Secrets and keys

Check 7: No secret keys in the code the browser downloads (Scanner)

Supabase service-role keys, Stripe secret keys (they start with sk_live_) and OpenAI keys must never reach the browser. Bots scan public sites and GitHub for them constantly.

Test: build the app, then search the output folder for service_role, sk_live, sk- and the names of your providers. Check source maps too.

Fix: move every call that needs a secret into a server route or edge function, and rotate every key that was ever exposed. Deleting it from the code is not enough.

Check 8: You know which variables ship to the client (Scanner)

Variables prefixed NEXT_PUBLIC_, VITE_ or EXPO_PUBLIC_ are copied into the app at build time. In a mobile app they are inside the file anyone can download from the store. Treat them as public, because they are.

Check 9: No hardcoded fallback secrets (Person)

Look for this pattern:

const SECRET = process.env.SESSION_SECRET ?? "my-app-secret-key";

We found exactly this in the marketplace audit. If the variable was ever missing, the server would sign login tokens with a value written in the source code, and anyone who had seen the code could create an admin login.

Fix: the app should refuse to start when a required secret is missing. No defaults.

Check 10: Your git history is clean (Scanner)

Removing a key from the code does not remove it from history. Run a secret scanner such as Gitleaks over the whole repository, and rotate anything it finds.

3. Sign-in and accounts

Check 11: Permissions are enforced on the server (Person)

Hiding the admin button from normal users is not security. If the API route behind it does not check the user's role, anyone who finds the route can use it.

Test: sign in as a normal user, open the browser's developer tools, and call an admin endpoint directly.

Check 12: Password reset and email verification actually work (Person)

AI tools are good at building the screens and sometimes skip the logic behind them. In the marketplace audit, "forgot password" and "verify email" both returned success and did nothing, and every new account was marked verified on creation. A user who forgot their password had no way back in.

Test: run each flow end to end with a real inbox.

Check 13: Sign-in, sign-up and costly actions are rate limited (Person)

Without a limit, one script can try thousands of passwords, flood your inbox with sign-ups, or run up your email, SMS and AI bills overnight.

Fix: add limits per user and per IP to sign-in, sign-up, password reset, anything that sends a message, and anything that calls a paid API. Add a CAPTCHA to public auth forms.

Check 14: Redirect URLs are locked to your domains (Scanner, partly)

In Supabase and most auth providers, set the site URL to your production domain (it often starts as localhost) and list exact redirect URLs. Wildcards that cover a shared hosting domain also match apps you do not own.

4. Payments and money

Check 15: Payment webhooks verify signatures and ignore duplicates (Person)

Stripe and Razorpay tell your server about payments through webhooks. If your handler does not verify the signature, anyone can send a fake "payment succeeded" event. If it does not record event IDs, a retried webhook can create a duplicate order.

Fix: verify the signature against the raw request body, store each event ID, and skip events you have already processed.

Check 16: Only the server grants paid access (Person)

In the marketplace audit, an endpoint took a plan ID from the request and wrote an active subscription, with no payment involved. Any user could give themselves the paid plan in one request.

Test: list every way an account gains access, credits or a plan, and confirm each one starts from a verified payment on the server.

Check 17: Multi-step changes happen all at once or not at all (Person)

Deleting an account in the marketplace app ran 16 separate delete statements across 14 tables, with no transaction. A failure halfway through would leave the account permanently broken. Sign-up had the same problem on a smaller scale.

Fix: wrap related writes in a database transaction.

5. AI features inside your app

If your app itself calls an AI model, these checks matter as much as the ones above.

Check 18: AI output is checked before it changes your data (Person)

In October 2026 we ran a one-day test of a fishing-harbour trade app that its product owner had built with AI coding agents. It has a voice-billing feature that turns a spoken sale into bill lines. In our test it produced a fully correct draft in only 2 of about 12 attempts.

What saved it was good design: the app validated every AI reply, refused malformed ones, and never added a line to a bill until a person reviewed it. That is the pattern to copy. Treat model output like user input, validate it against a schema, and keep a human approval step wherever money or records change.

Check 19: User content cannot instruct your AI (Person)

If your app sends user-written text to a model, assume someone will write "ignore your instructions and..." into it. Keep secrets and other users' data out of prompts, limit what the model's output can trigger, and never let it run actions with more permissions than the user who asked.

Check 20: Paid AI calls have a spending cap (Person)

Set a per-user limit and a daily cap in your code, and a hard budget at the provider. A single bot can otherwise turn a public AI feature into a four-figure bill.

6. Dependencies and the CVE wave

Vulnerability disclosures more than doubled this year. The US National Vulnerability Database lists over 86,500 CVEs published between 1 January and 25 October 2026, against 48,151 in all of 2025, according to an analysis by Brandefense. A vibe-coded app is pinned to whatever versions the AI chose on the day it wrote the code, and usually nobody is watching them. For what to patch in each stack right now, see CVEs doubled in 2026: what to patch in Next.js, Node.js and PHP.

Check 21: No known critical vulnerabilities in your packages (Scanner)

Run npm audit, pnpm audit, pip-audit or flutter pub outdated, depending on your stack, and fix anything critical or high first.

A real example: React2Shell (CVE-2025-55182), rated 10.0 out of 10, let attackers run code on the server of any unpatched Next.js 15 or 16 app using the App Router. The Next.js team's advice after patching was to rotate every secret the app used.

Check 22: Updates and alerts are automatic (Scanner)

Turn on Dependabot or Renovate for update pull requests, and GitHub secret scanning with push protection. Five minutes of setup, and you hear about the next critical bug the day it is published.

Check 23: Your framework is on a supported version (Scanner)

Old major versions stop getting security fixes. Check the support policy of your framework and runtime, and plan upgrades before the end-of-life date rather than after.

7. Production basics AI tools skip

None of these will leak data on their own, but each one turns a small incident into a big one.

Check 24: Schema changes go through migrations (Person)

Prototypes often change the database with a "push" command that syncs the schema directly. In the marketplace app, that was the only way schema changes were made, and on a live database it can drop a column, and the data in it, without warning.

Fix: use versioned migrations, keep them in the repository, and test them on a copy of production data.

Check 25: Backups exist and you have restored one (Person)

A backup you have never restored is a hope, not a backup. Restore one into a scratch project and time how long it takes.

Check 26: Errors are visible, and nothing is faked (Person)

Look for empty catch blocks and background jobs that log success without doing anything. Then look for hardcoded data. The marketplace app returned subscriptionStatus: "active" as a fixed string in six files, and its admin statistics were hardcoded zeros. Any test that read those values would have passed against a stub.

Fix: add error tracking such as Sentry, alert a human on failures, and delete any value that pretends to be real.

Check 27: Security headers, CORS and request limits are set (Scanner)

An open cors() call lets any website call your API from a visitor's browser. Restrict CORS to your own domains, add standard security headers, and cap request body and upload sizes.

Check 28: Mobile builds are store-ready (Person)

For an AI-built mobile app, check that release builds are signed with your own keystore, not the debug keystore a template ships with, that users can delete their account inside the app, which Apple requires for apps with sign-up, and that every permission prompt explains why the app needs it. These are common reasons for store rejection.

What scanners catch, and what they miss

AreaA scanner will usually findOnly a person will find
Data accessTables without RLS, open Firebase rules, public bucketsEndpoints that skip ownership checks, fields users should not be able to set
SecretsKeys in the bundle or git historyHardcoded fallback secrets that only apply when a variable is missing
Sign-inLoose redirect settingsServer-side permission gaps, reset and verification flows that do nothing
PaymentsLittleUnsigned webhooks, self-granted plans, missing transactions
AI featuresLittleUnvalidated model output, prompt injection paths, no spending cap
DependenciesKnown CVEs, outdated packagesWhether the fix needs a secret rotation or a code change
ProductionMissing headers, open CORSFaked data, silent failures, untested backups

Run the scanners first, because they are fast and free. Just do not treat a clean scan as a clean app. In our marketplace audit, the endpoints that leaked other businesses' data, the self-granted verified badge and the commented-out file check were all invisible to automated tools.

When to get a second pair of eyes

If you worked through this list and found several failures in sections 1 to 4, or you could not tell whether you passed, that is the point where an engineer reading the code pays for itself. Most of these are quick fixes once someone finds them. Finding them is the hard part.

We offer a free security audit for vibe-coded apps: read-only access, an NDA before you share anything, and a severity-ranked report with a rescue-or-rebuild verdict in under 24 hours. If you would rather start again on solid foundations, our AI-powered app development team builds apps with these checks in place from day one.

FAQ

How do I know if my vibe-coded app is secure?

Run the automated checks first: the Supabase Security Advisor or your database's equivalent, a dependency audit, and a secret scanner over the repository. Then do the two-account test from Check 3: try to read, change and delete one account's data while signed in as another. If any of that works, the app is not secure, whatever the scanners said.

Is Supabase secure enough for a production app?

Yes, when it is configured properly. The risk in vibe-coded apps is not Supabase itself but missing or overly broad row-level security policies, and service-role keys that end up in the browser. Checks 1, 2, 5 and 7 cover those.

Can a security scanner replace a code review?

No. Scanners are good at known patterns: missing RLS, exposed keys, vulnerable packages. They cannot tell whether a user should be allowed to see a particular record, whether a payment really happened before access was granted, or whether a success message hides a function that does nothing. Those need a person who understands what the app is supposed to do.

What should I fix first?

Anything that exposes other users' data (Checks 1 to 6), then exposed secrets (Checks 7 to 10, including rotating keys), then payments (Checks 15 to 17). Those three groups cover the failures that hurt customers and revenue directly.

How often should I re-run this checklist?

Re-run the scanner checks on every release, ideally automatically in CI. Re-run the person checks whenever you add a new data type, a new user role, a payment flow or an AI feature, and after any large AI-generated change, because regenerating code can quietly undo an earlier fix.

Building something like this?

Behind 400+ shipped projects is a team that sweats the details. Talk to our Chennai app development team and we'll send you a free roadmap for your app — scope, timeline, and budget included.

Get Your Free Roadmap

Keep reading

More insights from the blog

View all articles
CVEs Doubled in 2026: What to Patch in Next.js, Node.js and PHP
Engineering & Tech Trends

CVEs Doubled in 2026: What to Patch in Next.js, Node.js and PHP

Over 86,500 CVEs were published in 2026 by late October, nearly double 2025. Why, which few matter, and what to patch now in Next.js, Node.js and PHP.

Karthik Sakthivel Oct 29, 2026 12 min read
AI Workforce for SMBs: How AI Agents Handle Calls, Emails, Collections & Sales
Engineering & Tech Trends

AI Workforce for SMBs: How AI Agents Handle Calls, Emails, Collections & Sales

A practical guide to AI agentic workforces for SMBs — how AI calling, email, collections, and sales agents actually work, costs, and how to start.

Karthik Sakthivel Aug 19, 2026 9 min read
What Is LLM Integration? A Systems-Level Guide for Engineers
Engineering & Tech Trends

What Is LLM Integration? A Systems-Level Guide for Engineers

What LLM integration actually means beyond calling an API: orchestration, RAG, tool use, guardrails, cost trade-offs, and when each pattern breaks.

Karthik Sakthivel Aug 17, 2026 10 min read