VJOURNAL

AI • Global Desk •

Vibe coding security: what to check before an AI-built app meets real users

An app built with Cursor, Lovable, Bolt or v0 can run and still leak data. A plain guide to the holes that matter, a one-day check before launch, and how to decide between rescue and rebuild.

Drawing: a code window with one highlighted line next to a warning sign and a padlock

Answer in brief

An app made by prompting is built to work on screen, not to withstand a stranger. The usual holes are missing ownership checks, keys left in code or its history, and database tables with no row-level rules. A one-day test as an outsider finds the obvious ones. If fixes keep breaking other parts, a rebuild may be cheaper than a rescue.

6 sources
Prompted apps are tested by their author alone, so missing access checks stay invisible until a stranger arrives.
OWASP puts broken access control first in its Top 10:2021: users must not be able to act outside their permissions.
A leaked key stays in Git history after you delete it from the file; revoke it with the provider and issue a new one.

Why a working demo is not yet a safe app

Vibe coding security begins with a simple observation. You describe an app to Cursor, Lovable, Bolt or v0, the tool writes it, and it runs on screen. Nothing in that loop asks whether a stranger could open the same address and read somebody else's records. The demo passes because the one person testing it is also the owner of every row.

The risk grows on the day real users arrive. Real users bring real names, orders and payments. OWASP's Top 10:2021 list of web application risks shows that this is ordinary engineering rather than exotic hacking. The sections below walk through the weak points an AI-built app meets first, and what to check before launch.

Broken access control, the weakness OWASP lists first

In the OWASP Top 10:2021, broken access control stands in first place, up from fifth in the previous edition. OWASP defines the idea in one line: access control enforces policy such that users cannot act outside of their intended permissions. OWASP also notes that 94% of the applications in its data were tested for some form of it, so this is the common case, not a rare one.

In an app built by prompting, the gap can appear in a few recognisable places. A page is hidden from the menu but still opens when you type its address, which OWASP calls forced browsing. A request carries an account or order number, and changing that number shows another customer's record. A save, update or delete endpoint checks that the person is logged in but not that the record belongs to them. OWASP lists missing access controls on POST, PUT and DELETE among its examples.

The remedies in OWASP's guidance are plain. Deny by default, except for public resources. Enforce the rules in trusted server-side code, because the browser cannot police itself. Base access on who owns each record, and log failures so that someone notices repeated attempts. A hidden button is not a rule: if the only protection is that the admin link is not displayed, the app has no access control at all.

Keys and secrets that end up where everyone can read them

Every app that talks to a payment service, an email service or an AI model needs a secret key. Vercel's documentation describes environment variables as key-value pairs configured outside your source code, and that is the habit to look for. The failure to look for is the opposite: a key pasted into a file, committed to the repository, or shipped to the browser together with the page.

GitHub's documentation on secret scanning says it scans the full Git history of a repository, on all branches, for hardcoded credentials such as API keys, passwords and tokens. That has a consequence people miss. Deleting the key from today's file does not remove it from history. GitHub's guide on leaked secrets states that removing the secret from the codebase, pushing a new commit, or recreating the repository does not prevent misuse, and that any leaked secret should be considered compromised.

The fix is to revoke the key with its provider and issue a new one, which GitHub calls the most important remediation step. Then read the provider's logs for use you do not recognise, and keep the new key in the hosting platform's settings. Vercel adds a practical detail: a changed variable applies only to new deployments, so redeploy after rotating.

Open database rules and the Row Level Security trap

When an app connects the browser straight to a hosted database, the database rules become the only guard. Supabase's documentation on Row Level Security states the risk bluntly: a table in an exposed schema without RLS is readable and writable by any role with a grant on it. Turning RLS on is not the end of the job either. The same page says tables also need matching grants and policies, and that once RLS is enabled the API returns no data under a publishable key until a policy exists. A policy that simply says true for the anonymous role opens every row to every visitor, and the guide reserves that for public data.

The second point on that page concerns the powerful key. A secret key works through the service role, which skips Row Level Security, and the guide warns against using it in browsers or exposing it to customers. If an AI tool wrote the sign-in screen and the data calls in one go, check which key sits in the front-end code. Then test like an outsider: sign in as one user and try to read the rows of another. The guide itself recommends testing each table with allow and deny cases for each role.

Misconfiguration: defaults, error pages and leftovers

OWASP calls the next family security misconfiguration and gives three everyday examples. Default accounts and their passwords are still enabled and unchanged. Error handling reveals stack traces or other overly informative messages to users. Unnecessary features are enabled, such as extra pages, accounts or privileges. A generated project can carry all three: a demo admin, a debug route left from the first session, a raw error printed on screen.

OWASP's prevention advice reads like a tidy-up list. Start from a minimal platform without unnecessary features, components, documentation and samples. Build every environment the same way but give each its own credentials, so the test database and the real one never share a password. Then verify the settings with automated checks rather than memory.

A one-day vibe coding security check before the first customer

Start with five tests that need no tools. Log out and open the addresses of the private pages. Log in as an ordinary user and try the admin addresses. Change the number in a record's address and see whether a stranger's record appears. Create two test users and try to read, edit and delete each other's data. Finally, trigger an error on purpose and read what the page prints.

Then look at where things live. Search the repository and the browser's loaded files for anything that looks like a key. Confirm that production keys sit in the hosting settings, not in code. Confirm that production runs on its own database, separate from test data, and that someone besides the builder can sign in as administrator.

This is a smoke test, not an audit. OWASP and the platform documents above are the reference, and passing means you have not found the obvious holes, not that none exist. If the app handles payments, health data, children's data or the personal data of people in other countries, extra rules apply beyond this list. Check your own case with a lawyer.

Rescue or rebuild: how to decide with a written list

A rescue makes sense when the structure is readable, the pages map to real features and the problems found live in settings and a handful of endpoints. Fixing ownership checks, moving keys, adding database policies and tidying deployment is bounded work with a clear end.

A rebuild becomes the honest answer when every fix breaks something else, when nobody can say where the data is stored, or when the data model does not match how the business works. Then patches only add weight. Do not decide by gut feeling. Ask a reviewer who did not write the app for a written list of problems ranked by risk, and decide against that list. It turns an argument into a comparison.

What to prepare before ordering a rescue

A reviewer needs very little to start. Prepare access to the repository, the hosting account and the database, given through each platform's invitation feature instead of by sending passwords. Write one page on what the app must do, who uses it and what would hurt most if it failed. Rotate any key you had to share after the review. With that sheet ready, a vibe coding security review takes days instead of weeks.

VITON13 Studio offers a package called Rescue for an app built with AI. It covers a security review of the code and settings, bug fixes in the parts that break, deployment setup and a code clean-up so the next developer can read it. Before any payment the studio writes a free draft: a list of the top problems found. The price is fixed, from $113, and the work takes 5 to 10 working days.

Practical checklist

  • Open every private address while logged out and as an ordinary user, and note what loads.
  • Search the repository and its history for keys; revoke any you find and issue new ones.
  • Enable row-level rules on every table the browser can reach, then test with two users.
  • Keep production keys in the hosting settings and the production data apart from test data.
  • Ask a reviewer who did not build the app for a written, risk-ranked list of problems.

Questions and answers

Is an app built with Cursor, Lovable, Bolt or v0 safe to launch as it is?

Not by default. The tool aims at an app that works, and nothing guarantees it checked who may see which record. Run the one-day tests from this article, and have someone who did not build the app review the code and settings before customers arrive.

What should I do if an API key was committed to my repository?

Treat it as exposed. Revoke it at the provider first, create a new one, store it in your hosting settings, redeploy, and read the provider's usage logs for anything unfamiliar. Cleaning the Git history is a separate, optional step that comes after.

Is Row Level Security enough to protect my database?

No. Supabase's documentation says tables also need matching grants and policies, and that the secret key skips RLS entirely. Keep that key out of browser code and test every table with allow and deny cases for each role.

Can I fix the problems by asking the AI tool to make the app secure?

It can help with a specific, named issue, such as adding an ownership check to one endpoint. A general request leaves gaps because the tool cannot see your hosting settings, database policies or repository history. Treat its changes as drafts and test them.

When is it better to rebuild an AI-built app than to rescue it?

When every fix breaks something else, the data structure does not fit the business, or nobody can say where the data is kept. Otherwise a rescue is usually cheaper. A written list of problems ranked by risk is the fair way to compare.