Vibe coding security comes down to a short list of checks. Apps built with Lovable, Bolt, Replit, Cursor or Claude Code usually work. What they tend to skip is anything a demo never exercises, such as who can read which rows, which keys reach the browser, and what happens when somebody repeats a request ten thousand times. Below are 13 checks, each with a test you can run in about ten minutes, grounded in Supabase's documentation, the OWASP Top 10 and the vendors' own security pages, all read on 23 October 2026. Run them before you invite real users. You do not need to be a security engineer to do it, and most fixes are small once you know where the gap is.
Is vibe coding safe?
It is as safe as the access rules, keys and limits around the code, and those are the parts AI tools are least likely to get right unprompted. The failures cluster in predictable places.
Access control comes first. OWASP's Top 10:2025 puts Broken Access Control at A01, Security Misconfiguration at A02 and Software Supply Chain Failures at A03. In apps built on Supabase, which includes most Lovable apps and many Bolt apps, the browser talks to the database directly with a public key. Supabase's docs say a table in an exposed schema without row-level security is readable and writable by any role with a grant on it. The policies are the only thing between one user and another user's data.
This has happened in public. The NVD record for CVE-2025-48757 describes insufficient row-level security policies in Lovable-generated sites, through 15 April 2025, that let unauthenticated attackers read or write arbitrary tables. Lovable disputes it, on the grounds that each customer is responsible for protecting their own app's data. Either way, the fix sat in the customer's policies. Bolt's own database security docs warn that on a site without sign-in it may write policies that let any visitor view, add, change and delete data.
Packages can be invented. A study accepted at USENIX Security 2025 analysed 576,000 code samples and found hallucinated package names in at least 5.2% of commercial-model output and 21.7% of open-source-model output, 205,474 unique names in all. Anyone can register one of those names on npm or PyPI and wait.
Agents with production access can do damage. In July 2025 a Replit agent deleted a user's production database despite instructions to freeze code; The Register reported that Replit responded by separating development and production databases automatically. Replit's docs now say Agent cannot modify the production database.
The checklist
Thirteen checks in the order we would run them. The tests assume a Supabase backend where that matters; the same idea applies to any database your front end can reach.
| # | Check | What good looks like | How to test it in 10 minutes |
|---|---|---|---|
| 1 | Row-level security on every table | Every table in an exposed schema, usually public, has RLS enabled | In the Supabase SQL editor run select tablename from pg_tables where schemaname = 'public' and rowsecurity = false; and expect no rows. Then open Security Advisor and clear its errors. |
| 2 | Policies tested with the anon key | Signed out, a visitor reads only public data; user A cannot read or change user B's rows | Copy the publishable (anon) key from your live site, then request each table with curl as below. Sign in as user A and ask for user B's row by id. Expect an empty result or an error. |
| 3 | No secret key in the client | Only the publishable or anon key appears in browser code | Build the app and search the output folder for sb_secret_ and for the name of your service-role variable. Decode any eyJ... token you find, on your own machine, and check its role is anon. |
| 4 | No secrets in git history | Nothing sensitive was ever committed, or it has been rotated | Run a secret scanner such as Gitleaks or TruffleHog over the whole history, not only the current files. Rotate anything it finds before doing anything else. |
| 5 | Email verification and password reset | Sign-up needs a confirmed email; reset links are single-use and expire | Sign up with a fresh address and try to use the app before confirming. Request a reset and use the link twice. Check email confirmation is on in Supabase Auth settings. |
| 6 | Session handling | Signing out ends the session; tokens expire on a short clock | Copy your access token from the browser, sign out, and replay a request with it. Note how long it keeps working. Check sign-out on one device does what you expect on another. |
| 7 | Authorization on server routes and edge functions | Every server function checks who is calling and whether they own the record | Call each API route and edge function with no token, then with user A's token on user B's record. Hidden buttons do not count; the server must refuse. |
| 8 | Input validation | The server checks type, length and range, and never trusts a price or role sent by the browser | Submit a 10,000-character name, a negative quantity and <script> in a text field. In the browser's network tab, edit a request to change a price or a role and resend it. |
| 9 | Rate limiting | Sign-up, login, password reset, forms and AI endpoints refuse floods | Send 50 requests in a short loop to login and to any endpoint that calls a model. If all 50 succeed, there is no limit. |
| 10 | Dependencies and hallucinated packages | Every package exists, is the one you meant and has no known critical vulnerability | Run npm audit. For each package the AI added, check its npm page for publisher, weekly downloads, repository link and age. |
| 11 | Logging and error monitoring | Errors reach a person; logs are searchable and hold no passwords, tokens or card data | Throw a deliberate error in staging and time how long it takes for someone to be told. Search the logs for password and token. |
| 12 | Backups | Automatic backups exist and someone has restored one | Check your database plan's backup retention, then restore the latest backup into a scratch project and open a table. |
| 13 | Cost controls on AI API keys | Model keys stay on the server, the provider account has a spend limit, users have caps | Search the browser bundle for your model provider's key prefix. Confirm a monthly limit is set in the provider's console. Hit your AI endpoint 50 times signed out. |
How to test row-level security properly
Checks 1 and 2 matter most, so here is the full version. Your app's publishable key is meant to be public, so assume an attacker has it and test with it yourself.
- Find your project URL and publishable key in the site's network requests or the Supabase dashboard.
- For each table, request it signed out:
curl 'https://YOUR-PROJECT.supabase.co/rest/v1/orders?select=id' -H 'apikey: YOUR-PUBLISHABLE-KEY'. Anything that should be private must come back empty or refused. - Sign in as a test user, copy the access token, add it as an
Authorization: Bearerheader, and request another test user's rows by id. - Try writes too: an insert into another user's account, an update to someone else's row, a delete.
- Repeat for storage buckets. Supabase says anything in a public bucket is publicly accessible.
Four details from Supabase's RLS guide catch people out. auth.uid() returns null when nobody is signed in, so add an explicit auth.uid() is not null check. Policies that rely on user_metadata are unsafe because signed-in users can edit that claim; Supabase recommends raw_app_meta_data for authorization data. Views bypass RLS by default; on Postgres 15 and later, set security_invoker = true so a view obeys the policies of its tables. And add an index on every column your policies filter on, or the checks will slow every query.
Which key goes where
Supabase has two kinds of key. The publishable key (the legacy name is anon) is safe to expose in a web page or app and reaches only what your policies allow. The secret key (legacy: service_role) bypasses every row-level security policy, and Supabase says never to put it in a browser, a shipped app or source control. Supabase blocks secret keys sent from browsers, but a leaked one still works from any other tool.
If a secret key leaked, create a new one, replace it everywhere, confirm every component uses it, then delete the old one. GitHub's guidance on removing sensitive data is to revoke or rotate the secret first; once it is rotated, rewriting history may not be needed. Payment, email and model API keys follow the same rule. Keep them in the builder's secrets store (Lovable Secrets, Bolt's database secrets, Replit Secrets) and call those services from a server function, never from the browser.
Auth, limits and cost caps
Supabase's production checklist asks for email confirmations, an OTP lifetime of 3,600 seconds or less, a custom SMTP server for auth emails and multi-factor authentication on your own Supabase account. It also lists the default auth rate limits; auth emails, for example, are limited to 2 an hour until you set up custom SMTP. Those limits protect Supabase's auth endpoints only. Your own API routes and edge functions need their own.
AI features add a cost risk. OWASP's LLM list names it Unbounded Consumption (LLM10), next to Sensitive Information Disclosure (LLM02). An endpoint that calls a model with no sign-in and no limit lets anyone spend your money. Put a per-user cap in your own code and a monthly ceiling at the provider; Anthropic, for example, lets you set a spend limit below your tier's cap in its console.
Backups and recovery
On Supabase, daily backups are kept for 7 days on Pro, 14 on Team and up to 30 on Enterprise. Free projects are not in that list; Supabase recommends they export their own data regularly with the CLI. Replit's docs describe point-in-time database restore within 7 days as standard and 28 days on Pro. Whatever you run on, a backup nobody has restored is a hope, so do one restore before launch.
What the builders' own scanners catch
All three app builders now scan. Lovable runs a Quick scan on every publish and offers a manual Deep scan of the code. Bolt's project security audit checks data access, sign-in, misuse and keys. Replit's Project Security Center adds dependency scans and Agent security scans. Use them; they are free or close to it. They also say plainly what they are not. Lovable's docs say its scans cannot guarantee complete security, and Replit's say a clean scan does not guarantee an application is secure. Our Lovable vs Bolt vs Replit comparison sets the three side by side.
AI code review helps, and it is not the whole job
If you work in Cursor or Claude Code, AI code review is a cheap first pass. Claude Code's /security-review command runs an on-demand security pass over the changes on your current branch, and Cursor's Bugbot reviews pull requests on GitHub. Both read code. The checklist above tests behaviour: what the running app does when someone signed out asks for your orders table. Run both, and treat a clean AI review as a reason to run the tests, not to skip them. Our Claude Code vs Cursor comparison covers the two assistants.
Taking it to production
Most prototypes, demos and side projects do not need a paid review. Work through the table, fix what fails, and ship. A review earns its fee when the app will hold other people's data, take payments, or face a customer's security questionnaire or an investor's diligence.
That is what our Prototype Production Review is for. In the service page's own words, "a senior engineer reviews its security, data model, performance and deploy", and in 5 business days you get a graded report and a fix plan. The checks cover row-level security that is off or too broad, the wrong key in the browser, auth and sessions, storage bucket permissions, input validation and rate limits, and secrets in the repository; then schema, migrations and backups; queries, page weight and what the app costs to run; and environments, error monitoring and who owns the accounts. It is $2,500 fixed, credited in full to a build with us started within 60 days. It is not a penetration test or a compliance certification, and fixes are separate: you can make them yourself, or an embedded team does them at $3,000–$7,500 per engineer per month. For AI features with their own attack surface, such as prompt injection or agents with tool access, see our AI security assessment.



