Tools
Vibe coding security checklist before launch, written for product people
Do not put a vibe coded app in front of real users until ten checks pass, and the first four decide most outcomes: row level security on every table, no secret keys in the browser bundle, permission checks on the server, and rate limits on anything that costs money. Veracode found AI-generated code introduced security flaws in 45 percent of its test cases, so treat every one of these as unverified until you have tested it yourself.
Vibe coded apps fail security in predictable places, and you can test most of them without reading code. Veracode's 2025 GenAI Code Security Report analysed 80 curated coding tasks across more than 100 large language models and found AI-generated code introduced security vulnerabilities in 45 percent of cases. Jens Wessling, Veracode's CTO, says the problem with vibe coding is that "The main concern with this trend is that they do not need to specify security constraints to get the code they want, effectively leaving secure coding decisions to LLMs."
The test cases are synthetic coding tasks, not live apps, so 45 percent is not the share of launched products that are breachable. Real apps show the same pattern, though. Matt Palmer's statement on CVE-2025-48757 reports that an automated scan "identified 303 endpoints across 170 projects (approximately 10.3% of the 1645 analyzed) with inadequate RLS settings" among Lovable-built sites in March 2025. Lovable disputes the CVE: the National Vulnerability Database record notes the supplier's position that each customer is responsible for protecting their own application's data. Read that dispute as the lesson. Whoever is right about blame, the person launching the app owns the outcome.
What does the full pre-launch checklist look like?
The checklist has ten items, ordered by how much damage a miss causes. Each one names the test a product person can run, not just the setting to change.
| Number | Check | How you test it without reading code |
|---|---|---|
| 1 | Row level security is on for every table | Open your database dashboard and confirm no table is marked as RLS disabled |
| 2 | Policies enforce ownership | Log in as user B and try to load user A's record by changing the ID in the URL |
| 3 | No secret key in the browser | Search the deployed JavaScript for your secret key prefixes |
| 4 | Permission and payment checks run on the server | Try to set a "paid" or "admin" field from the browser and see if it saves |
| 5 | Paid API calls go through a server function | Confirm your LLM or email key never appears in browser network requests |
| 6 | Rate limits on login, sign-up, forms and paid calls | Submit the same form 50 times quickly and check that it starts refusing |
| 7 | Secret scanning is on and old keys are rotated | Check the repository's security settings and your provider key list |
| 8 | Dependencies are reviewed | Open the dependency alerts on your repository and clear critical ones |
| 9 | User input is displayed as text, not code | Type a bold HTML tag into a text field and check it does not render bold |
| 10 | Failures are logged and someone is alerted | Trigger a failed login or denied read and find it in the logs |
Items 1 to 4 cover the failures in the incidents cited on this page: tables without RLS, a payment field the browser could write, and exposed keys. If time is short, do those four and delay launch on the rest rather than skipping them.
Why is row level security the first thing to check?
Row level security (RLS) is the database rule that decides which rows each signed-in user can see, and in an app whose front end talks to Supabase directly it is the only thing standing between the browser and your whole database. The Supabase Row Level Security docs are blunt: "A table in an exposed schema without RLS is readable and writable by any role with a grant on it." The same page says to "Enable RLS on every table in an exposed schema."
Palmer's CVE write-up explains why vibe coded apps are exposed here specifically. The generated front end calls the database directly from the browser with a public key, and relies on RLS to keep each user's data private. When a table has RLS switched off, or a policy that is too loose, anyone who opens the browser's network tab can change the request and ask for every row.
Turning RLS on is half the job. Supabase notes that "Once RLS is enabled, no data is accessible through the API when using a publishable key, until you create policies." The usual failure after that is an AI tool writing a policy that lets any signed-in user read everything, just to make the error go away.
How do you prove access control works without reading the code?
You test it as an attacker would: as a stranger, then as the wrong customer. OWASP's Top 10:2025 keeps broken access control at number one and states that "100% of the applications tested were found to have some form of broken access control." Its prevention advice is short: "Except for public resources, deny by default."
Run three tests on a staging copy with fake data:
- The logged-out test. Sign out, then open every page and every link that shows user data. Anything that loads is public.
- The neighbour test. Create two accounts. As user B, take a URL or record ID that belongs to user A and load it. If you see A's data, your policies check that a user is signed in but not which user.
- The edit test. As user B, try to change or delete user A's record. Read access and write access are separate policies, and AI tools often get one right and the other wrong.
A pass on all three does not prove the app is secure. It proves the most common failure is not present, which is the right bar for a first launch.
Where do secret keys leak in a vibe coded app?
Secret keys leak into the JavaScript the browser downloads, and from there anyone can copy them. Escape's research on vibe coded apps analysed over 5,600 publicly available applications and reported more than 2,000 vulnerabilities, 400+ exposed secrets and 175 instances of personal data, including medical records and IBANs.
Know which keys are meant to be public. A Supabase anon or publishable key is designed to sit in the browser; Palmer's statement says the core issue in the Lovable case "was not an exposed public API key as we initially thought." The dangerous ones are your Supabase secret or service_role key, your Stripe secret key, and any LLM provider key. On the secret key, the Supabase docs say: "Never use a secret key in the browser or expose it to customers," because a secret key can bypass RLS.
If your app is a Vite project (look for a vite.config file in the code), Vite's environment variable docs state that "Variables prefixed with VITE_ will be exposed in client-side source code after Vite bundling." If an AI tool fixed an error by renaming your OpenAI key to start with VITE_, the key is now public. The fix is to move the call into a server or edge function and keep the key in the host's environment settings, which deploying an AI-built app for the first time walks through step by step.
Which checks have to live on the server, not in the browser?
Anything that decides money, roles or limits has to be checked on the server, because the browser is fully under the user's control. OWASP's guidance says "Access control is only effective when implemented in trusted server-side code or serverless APIs, where the attacker cannot modify the access control check or metadata."
Palmer's follow-up test shows the cost of getting this wrong. On one Lovable-built site he reports inserting a record with "payment_status": "paid" directly through the database API, bypassing the Stripe integration. The app had a payment flow; it just trusted the browser to report the result.
For a product person, the rule translates into three questions to ask your AI tool, one at a time:
- Where is the check that this user has paid, and does it run in a server function or a webhook?
- Can a user change their own role, plan or credit balance by editing a request?
- Which endpoints call a paid API, and is there a per-user limit on each one?
If the honest answer to any of these is "in the front end," that feature is not ready for real users.
Why do rate limits matter on a small launch?
Rate limits stop one script from doing the damage of a thousand users, and small apps are cheap targets. OWASP's A01:2025 prevention list includes the instruction to "Implement rate limits on API and controller access to minimize the harm from automated attack tooling."
The costs are concrete. An unprotected sign-up form fills your user table with junk. An unprotected "generate" button that calls an LLM is a way for someone else to spend your API budget. An unprotected login form invites password guessing. Set a per-user and per-IP limit on each of these, and set a hard spending cap in your LLM provider's billing settings as a backstop the code cannot override.
What about secret scanning and dependencies?
Secret scanning and dependency alerts are the two checks you can switch on once and leave running. GitHub's secret scanning docs say it "automatically detects credential leaks so you can secure them before they're exploited," and for public repositories it runs automatically for free. If a key was ever committed, rotate it at the provider. Deleting it from the latest version does not remove it from the repository history.
Dependencies are the packages your AI tool installed without asking. OWASP's A03:2025 Software Supply Chain Failures says you are likely vulnerable if "you do not carefully track the versions of all components that you use." On GitHub, Dependabot alerts flag a vulnerable dependency on the repository's Security and quality tab, with information about a fixed version when one is available. Before launch, clear the critical and high alerts, and ask your AI tool to explain any package you do not recognise.
Does user input need its own check?
User input needs its own check because cross-site scripting is a weakness the models Veracode tested rarely handled. Veracode reports that the models it tested "failed to secure code against cross-site scripting (CWE-80) and log injection (CWE-117) in 86 percent and 88 percent of cases, respectively."
The product-level test takes a minute. In every field that other users will see (names, comments, profile bios), enter a simple bold tag around a word. If the word shows up bold anywhere, the app is rendering user input as HTML, and a malicious user could put a script there instead of a bold tag. Ask your AI tool to display all user content as plain text and to explain where it changed the rendering.
Is a checklist enough, or do you need a security review?
A checklist is enough for an internal tool or a prototype with fake data, and not enough for anything that takes payments or stores sensitive personal data. Veracode's testing suggests waiting for better models will not close the gap; Wessling says "We also found larger models do not perform significantly better than smaller models, suggesting this is a systemic issue rather than an LLM scaling problem."
The checks above find configuration mistakes: a missing policy, a public key that should be secret, a missing limit. They do not find flawed business logic, such as a discount rule that can be stacked or an invite flow that grants the wrong role. If the app handles money, health data, children's data or other people's personal data, pay for a review by someone who reads code before launch, and treat this checklist as the work you finish first so the review is spent on harder problems.
How does the checklist fit into the rest of the build?
Security checks work best as a stop line before each release, not a one-off audit. The habits in vibe coding mistakes to avoid, such as building one feature at a time and saving a checkpoint before each change, make the checklist faster to rerun, because you know exactly what changed since the last pass. When a test fails and you cannot see why, debugging AI-generated code covers how to get the AI to explain the failing path in plain language.
Your coding agent is a security surface too. If it can run commands or connect to outside tools, Claude Code permissions and safety and MCP security for product teams cover what to allow and what to deny before it touches production credentials.
Zero to Shipped with Vibe Coding is a one-week Builders Camp bootcamp, with 2 live sessions and 11 self-paced microlessons, for going from idea to a working MVP with AI-assisted building tools, including connecting data storage and services such as payments and auth, and shipping it safely to early users. It sits in the Vibe Coding Expert Track and, like every Builders Camp bootcamp, is led by its own programme director.
Bootcamps referred in this Guide
Frequently asked questions
What is the single most important security check for a vibe coded app?
Turning on row level security for every table the browser can reach, then proving it works by trying to read another user's data while logged in as someone else. Supabase's own docs say a table in an exposed schema without RLS is readable and writable by any role with a grant on it, and a widely reported vibe coding leak, CVE-2025-48757, was exactly that failure.
Is it a problem that my Supabase anon or publishable key is visible in the browser?
No, that key is designed to be public. Matt Palmer's write-up of CVE-2025-48757 makes the same point: the issue was never the public key but missing RLS. The key that must never reach the browser is the secret or service_role key, which Supabase says can bypass RLS.
How do I check whether a secret key ended up in my front end?
Open the deployed site, open the browser developer tools, and search the loaded JavaScript files for the start of each key you hold (sk_, service_role, your LLM provider's key prefix). In a Vite project, anything in a variable starting with VITE_ is bundled into the client, so no secret belongs in one.
Does the security scanner in my vibe coding tool replace this checklist?
No. A scanner that confirms a policy exists cannot tell whether the policy matches your business rules. Palmer's statement on CVE-2025-48757 criticised an early Lovable scanner on exactly that point. Use the tool's scanner, then run the manual tests in this checklist anyway.
Why do I need rate limits on an app with ten users?
Because rate limits protect you from scripts, not from your ten users. Any endpoint that calls a paid LLM API, sends email or creates accounts can be called thousands of times by one person with a loop. OWASP's 2025 guidance lists rate limits on API access as a control against automated attack tooling.
When does a vibe coded app need a real security review instead of a checklist?
When it takes payments, stores health, financial or children's data, or handles personal data for people outside your own team. A checklist catches common configuration mistakes. It does not catch flawed business logic, and Veracode's testing found vulnerabilities in 45 percent of AI coding test cases, and larger models did not do significantly better.
What should I do if I find a leaked key after launch?
Rotate it first at the provider, then remove it from the code, then check the provider's usage logs for calls you did not make. Deleting the key from the latest commit is not enough, because it stays in the repository history and in any copy someone already pulled.
Sources
- Veracode press release: 2025 GenAI Code Security Report (July 30, 2025)
- Matt Palmer: Statement on CVE-2025-48757 (May 29, 2025)
- National Vulnerability Database: CVE-2025-48757
- Supabase Docs: Row Level Security
- OWASP Top 10:2025, A01 Broken Access Control
- OWASP Top 10:2025, A03 Software Supply Chain Failures
- Vite Docs: Env Variables and Modes
- GitHub Docs: About secret scanning
- GitHub Docs: About Dependabot alerts
- Escape: Methodology, how we discovered over 2k high-impact vulnerabilities in apps built with vibe coding platforms (October 29, 2025)

Tiago Pedro da Costa
As Co-founder & CTO of Zumer, Tiago builds platforms that leverage AI to automate knowledge, improve collaboration, and accelerate sustainability in the construction industry. His work ranges from Abaqus, a platform for project and site management, to an AI-powered assistant supporting BREEAM certification.
As Co-founder & CTO of Zumer, Tiago builds platforms that leverage AI to automate knowledge, improve collaboration, and accelerate sustainability in the construction industry. His work ranges from Abaqus, a platform for project and site management, to an AI-powered assistant supporting BREEAM certification.
LinkedInMore guides by Tiago Pedro da CostaLast updated 2026-10-12
Researched from Builders Camp's bootcamp, track and masterclass material and the sources listed on this page, drafted with AI, and fact-checked against every source cited.
Related guides
Vibe coding mistakes to avoid, and the fix for each
The costly vibe coding mistakes are product mistakes, not coding ones: building before you know the problem, letting...
Andre AlbuquerqueHow to deploy an AI built web app for the first time: hosting, environment variables and a production checklist
Pick the host by what your app is, not by brand: a front end that talks to a hosted database deploys as a static site...
Gonçalo SoaresHow to debug AI generated code when you are not an engineer
Debug AI generated code with a fixed loop: reproduce the bug on purpose, read the full error, ask the AI to explain...
Andre AlbuquerqueMCP security for product teams, and the approval boundary to agree first
The MCP specification names user consent, data privacy and tool safety as key principles and then states plainly that...

Andre Albuquerque & Inês LourençoClaude Code permissions and safety for product teams
Permission rules are evaluated deny, then ask, then allow, and a deny at any level cannot be overridden anywhere else...

Andre Albuquerque & Inês Lourenço
