Security check for your vibe-coded app: is your data exposed?

You built an app with Lovable, Bolt, Cursor or similar (usually on Supabase) and want one tool to tell you, before launch, whether it leaks data or secrets, and what to fix.

Published Oct 16, 2026 Last tested: Oct 16, 2026 Verdict: final Test log (9 entries)

Short answer: No free scanner we tested caught most of our 10 planted security holes. Run Supabase's built-in Security Advisor (76/100, caught 3, with copy-paste SQL fixes), then check by hand the five things every tool missed: policies that let any logged-in user read everyone's rows, public storage buckets, unprotected Edge Functions, unsafe HTML rendering and outdated packages.

The verdict

Winner

Supabase Security Advisor

76/100

The security checks built into every Supabase project (Dashboard → Advisors → Security Advisor).

Caught 3 of our 10 planted holes, the most of any tool: the table with RLS off, a view exposing user emails from auth.users, and a SECURITY DEFINER function anyone could call. Every finding links to a fix page with copy-paste SQL, and after we applied the fixes a rescan cleared all three. One false alarm: it flagged the standard new-user trigger function as callable through the API (the call actually fails). Free and built in, with nothing shared outside Supabase. But it only looks at the database: it missed the loose "any logged-in user" policy and the public bucket, and it can't see your code, bundle or functions. Score: 76/100.

Visit Supabase Security Advisor

Runner-up

Semgrep Community Edition

63/100

A free, open-source code scanner you run in your project folder (semgrep scan .).

Caught the two leaked secrets in our code: the service-role key hardcoded in front-end JavaScript, and the Stripe-style key in a committed .env. Free, no account, and your code stays on your machine. But it also flagged the harmless public anon key at the same severity (1 false alarm), its findings say "detected" with no fix steps, it needs a terminal and Python, and it can't see your database, so it missed every Supabase setting we got wrong. Same result on both runs. Score: 63/100.

Visit Semgrep Community Edition

Also tested

Tested on the same app but not picked. The reasons are in the write-up below.

Quick answers

Will a scanner catch everything?

No. In our test the best single tool caught 3 of 10 planted holes, and all five tools together caught 5. Every tool missed a loose policy that let any logged-in user read and edit every profile, a public storage bucket anyone could list and upload to, an Edge Function with no login check, unsafe HTML rendering (XSS) and a vulnerable lodash version.

How do I check if my Supabase RLS is set up right?

Run Security Advisor (Supabase dashboard, Advisors, Security Advisor) to find tables with RLS turned off. Then test the policies yourself: sign in as a second test user and try to read or change the first user's rows. In our test, Security Advisor flagged the table with RLS off but not the policy that let any signed-in user read every profile; only the second-user test caught that.

Is my Supabase key exposed?

Any secret key in your front-end code is exposed: anyone can read it in your JavaScript. For Supabase, the anon or publishable key is meant to be in the browser, per Supabase's docs. The service_role or secret key must never be, because it bypasses RLS. In our test, Semgrep and Prodable's free scan both found the service-role key we planted in the front-end code; Semgrep also flagged the harmless anon key the same way. GitHub's secret scanning didn't flag it.

What does "RLS disabled" mean, and how bad is it?

Row Level Security is Postgres's per-row access rule. With RLS off on a table in the public schema, anyone with your project URL and public key can read, edit and delete every row, per Supabase's docs. On our test app we confirmed it: an anonymous request read and added notes. Security Advisor flagged it as an error.

Does GitHub's free security scanning catch these?

Partly. On a public repo, GitHub's push protection blocked our push because of the Stripe- and OpenAI-style keys in a committed .env, with no setup. But CodeQL found nothing in our code (not the XSS), secret scanning didn't flag the Supabase service-role key, and Dependabot raised no alert for our vulnerable lodash within the hour we allowed (its alerts only appeared after our next push). On private repos, code scanning and secret scanning are paid add-ons.

Is my vibe-coded app (Lovable, Bolt, Cursor) secure?

We can't say from a scan, and neither can any tool we tested; the most a scan shows is that it passed the checks it ran. Lovable has its own built-in security scan, described in Lovable's blog. We haven't tested it yet; Lovable is human-tested only on this site. Run Security Advisor on your Supabase project and do the second-user check.

What's on a vibe coding security checklist?

Run Security Advisor, then check by hand the five things no tool caught in our test: policies that compare the row owner to the signed-in user (not just "signed in"); storage buckets private, and never listable or uploadable by anonymous users; every Edge Function or API route checks who's calling; no user text rendered as raw HTML; and npm audit shows no known-vulnerable packages. Also make sure no secret or service_role key is in front-end code or a committed .env.

Why

Who this is for: you built an app with Lovable, Bolt, Cursor or another AI tool, it stores data in Supabase, and you want to know before launch whether strangers or other users can read your data or find your keys.

The honest headline: no free scanner we tested caught most of the holes we planted. We built a small Supabase app with 10 common security holes and ran five free tools on it (2026-10-16). The best caught 3. All five together caught 5. Every tool missed the other five: a policy that lets any logged-in user read and edit everyone’s profile, a storage bucket anyone could list and upload to, an Edge Function with no login check, user text rendered as raw HTML (XSS), and a known-vulnerable package. Check those five by hand (checklist below).

Our pick: Supabase Security Advisor (76/100). It’s built into every Supabase project, caught the most holes (3 of 10), and every finding came with a copy-paste SQL fix. Semgrep Community Edition (63/100) is the runner-up for your code: free, it runs on your machine, and it found both leaked secrets in our code. Use them together. They look at different layers, and between them they caught all five holes that any tool found.

Why Supabase Security Advisor

  • What it caught: our notes table with RLS off, a view leaking every user’s email from auth.users, and a SECURITY DEFINER function anyone could call to delete other people’s notes. After we ran the SQL from its fix pages, a rescan came back clean for all three.
  • What it can’t see: it only reads your database settings. Code, the JavaScript bundle, Edge Functions and dependencies are out of its reach.
  • A surprise: Supabase documents checks for “always-true” policies (lint 0024) and listable public buckets (lint 0025), but neither fired on our project, which had both. Same result on a second run.
  • When to add Semgrep: you have the code locally and can open a terminal. It’s the tool that caught secrets in code. Expect to ignore its warning about the public anon key, which is meant to be in the browser.

Vibe coding security checklist: five things every tool missed

  1. Policies that check the owner, not just “signed in”. Create a second test user, sign in as them, and try to read or edit the first user’s rows (from your app or the Supabase API). If it works, your policy says using (true) or only checks authenticated. Policies should compare auth.uid() to the row’s owner column, per Supabase’s RLS docs.
  2. Storage buckets. In Storage, every bucket should be private unless its files are truly public. Even public buckets shouldn’t allow anonymous listing or uploads: remove select/insert policies on storage.objects that are open to anon. To test, try listing the bucket and uploading a file while signed out.
  3. Edge Functions and API routes. Call each function with no login (for example, open its URL or use curl without an Authorization header). It should refuse. Keep “Verify JWT” on, and inside the function use the caller’s token rather than the service-role key, so RLS still applies.
  4. Raw HTML from users (XSS). Search your code for dangerouslySetInnerHTML, innerHTML and v-html. Anything a user typed should be rendered as text. To test, save a note containing <img src=x onerror=alert(1)> and see whether an alert pops up.
  5. Known-vulnerable packages. Run npm audit and update what it flags. On our app, lodash 4.17.21 still had advisories; 4.18.1 cleared them. GitHub’s Dependabot didn’t alert us until our next push, so don’t wait for it.

Also check what the tools did catch: RLS on every table, no secret or service_role key in front-end code or a committed .env (if one ever shipped, rotate it; deleting the line isn’t enough, and it stays in git history), and no view or function exposing auth.users.

What we planted and what each tool caught

#Planted holeSecurity AdvisorSemgrep CEGitHub (public repo)ProdableVibeScan
V1Table with RLS off (anyone can read/write)✔✘✘✘ said RLS looked correct✘
V2Policy lets any logged-in user read/edit every profile✘✘✘✘✘
V3Service-role key in front-end code✘✔✘✔✘
V4Committed .env with Stripe/OpenAI-style keys✘✔✔ (push blocked)✘✘
V5Public bucket anyone can list and upload to✘✘✘✘✘
V6Edge Function with no login check✘✘✘✘ said API routes required auth✘
V7View exposing auth.users emails✔✘✘✘✘
V8User text rendered as HTML (XSS)✘✘✘✘✘
V9Vulnerable lodash version✘✘✘ (no Dependabot alert in 60 min)✘✘
V10SECURITY DEFINER function callable by anyone✔✘✘✘✘
Caught32110 (no report)
False alarms11000
False all-clears00020

Wrong all-clears count against a tool

A scanner that says “you’re fine” when you aren’t is worse than one that says nothing, because you stop looking. Before any re-run, we amended our test script (v1.1, 2026-10-16 02:03 ET): a false all-clear, where the report says a check passed while that planted hole was open, costs twice a false alarm. We applied it to every tool’s first-run evidence. Only Prodable had any (two: “Row-Level Security looks correct” while our notes table was open to anyone, and “API routes require authentication” while our admin function wasn’t). Its score fell from 66 to 57, which moved it from runner-up to “also tested”. Saying nothing about a hole counts as a miss, not an all-clear.

The other tools

  • GitHub code scanning, secret scanning and Dependabot (60/100): free on public repos. Push protection blocked our first push because of the Stripe- and OpenAI-style keys in .env, with no setup at all, which is the best moment to catch a leak. But CodeQL’s default setup found nothing in our code, secret scanning didn’t flag the Supabase service-role key, and Dependabot raised no alert for the vulnerable lodash within our 60-minute limit, although GitHub’s dependency graph listed it. GitHub’s docs say alerts are created as soon as you turn Dependabot on; ours appeared only after the next push, by which time lodash was fixed (it then flagged real advisories in our vite and esbuild dev tools instead). On a repo you keep pushing to, it would probably have caught lodash on the next commit. We didn’t test that. On private repos, code scanning and secret scanning need paid GitHub Code Security or Secret Protection on a Team plan (Dependabot alerts stay free).
  • Prodable (57/100): a free scan of your live URL. It found the service-role key in our JavaScript bundle within seconds (after you enter an email), with a correct fix and no false alarms. But that was its only catch, and it gave the two wrong all-clears above. Fuller guidance is a $27 Deep Scan.
  • VibeScan (54/100, skip): couldn’t scan our app. Every attempt ended “blocked / too little evidence” with no findings.

Going live on your own domain next? See put your app on your own domain. For email confirmation and password rules, see add login to your app.

Supabase’s keys are changing

Supabase says it is deprecating the legacy anon and service_role keys “by the end of 2026”, in favour of publishable (sb_publishable_…) and secret (sb_secret_…) keys (API keys docs, checked 2026-10-16). The rule doesn’t change: publishable keys can be public, secret keys never can.

Scores

Criterion (weight)Security AdvisorSemgrep CEGitHub (public repo)ProdableVibeScan
Holes caught of 10 (35)2 (3/10)1 (2/10)1 (1/10)1 (1/10)1 (0, no report)
False alarms + false all-clears ×2 (15)4 (1)4 (1)5 (0)2 (0 + 2×2)5 (none)
Steps to first report (10)5 (3)5 (3)3 (6)4 (4)4 (4)
Time to report (10)5 (<1 min)5 (~1 min)5 (~3 min)5 (<1 min)1 (none)
Cost and free tier (10)553 (paid on private repos)4 (email needed)5
Fix guidance (10)5 (4 of 4)2 (1 of 4)4 (3 of 4)4 (3 of 4)1 (0 of 4)
Privacy (10)554 (code must be public to be free)55
Total /1007663605754

Our rule calls for a second run when the top two are within 10 points. Before the v1.1 change, they were exactly 10 apart (76 vs 66), and we count that as within. So after the change we re-ran the top two, Security Advisor and Semgrep, on a fresh copy of the vulnerable app. Both returned identical findings, so the averages equal the first-run scores.

What it costs

  • Security Advisor: included in every Supabase project, including Free.
  • Semgrep Community Edition: free and open source (LGPL 2.1). Dependency scanning is part of Semgrep’s AppSec Platform, not the free CLI.
  • GitHub: code scanning and secret scanning are free on public repos; on private repos they’re paid add-ons on a Team or Enterprise plan. Dependabot alerts are free everywhere.
  • Prodable: the scan is free. An email unlocks the full list. Deep Scan is $27 one-time (shown on our report, 2026-10-16).
  • VibeScan: the URL scan is free.

Caveats

  • A clean scan is not a guarantee. It means the tool found nothing with the checks it ran.
  • One small test app, planted holes. Real apps have more tables, functions and code paths. Tools may do better or worse on them.
  • Each tool looks at a different layer (database, code, repo, live site). Our score asks which single tool does the most for a vibe coder, but the table shows how to combine them.
  • Dummy keys: every planted key was a correctly formatted fake. A scanner that tests keys against the provider would find them invalid. This may have affected Prodable’s RLS probe and which keys GitHub flagged (we can’t see how either works). A real leaked key would be valid.
  • GitHub run: we used a separate public copy of the app and let the dummy keys through push protection with the “used in tests” reason. The copy has been archived.
  • Agent runs: an agent ran every tool through its official interface. For Security Advisor we used Supabase’s MCP server, which runs the same checks as the dashboard; for GitHub we used its official CLI and API, which flip the same settings as the dashboard.

Not tested

  • Snyk: not tested, because its terms ban publishing benchmarks.
  • Aikido (free tier): not tested yet. It needs the site owner’s GitHub account connected.
  • Lovable Security Scan: not tested yet. Lovable describes a Security Scan and a Security Reviewer in its own blog (published June 9, 2025). Lovable runs on this site are human-tested only, and we haven’t done one.

Test log

DateAgentStepResult
Oct 16, 2026Lando (agent)Built the test app (branch vuln-lab, tag vuln-lab-v1): Vite + React + supabase-js plus one Edge Function on a throwaway Supabase project with fake data, live on Cloudflare Pages. Planted 10 issues (V1–V10) and 4 safe decoys. Every planted key is a dummy.Our own check script confirmed all 10 holes were exploitable before any scan (anonymous read/write, cross-user read, key in bundle, anonymous bucket upload, open function, exposed emails, XSS, vulnerable lodash, anonymous delete through an RPC). Decoys were safe.
Oct 16, 2026Lando (agent)Supabase Security Advisor (run j05-supabase-advisor-r1, via Supabase MCP get_advisors, the same checks as the dashboard).Report in under a minute. Caught V1 (RLS off on notes), V7 (view exposing auth.users), V10 (SECURITY DEFINER function callable by anon). 1 false positive (the new-user trigger function). Missed V2 and V5, although Supabase documents lints for both (0024, 0025). They didn't fire on our project.
Oct 16, 2026Lando (agent)Semgrep Community Edition 1.181.0, semgrep scan . per the quickstart (run j05-semgrep-ce-r1).About a minute including install. Caught V4 (Stripe-format key in a committed .env) and V3 (hardcoded JWT in admin.js). Flagged the harmless anon key the same way (1 false positive). Findings say "detected" with no fix steps. No dependency scan in the free CLI.
Oct 16, 2026Lando (agent)Prodable free scan of the live URL (run j05-prodable-r1).Report in about 8 s, grade D 38/100. The service-role key in the bundle was shown only after we entered an email. Reported RLS and API routes as fine while V1 and V6 were open. Caught 1 of 10, 0 false positives.
Oct 16, 2026Lando (agent)VibeScan free URL scan (run j05-vibescan-r1), plus one retry and one post-fix attempt.All three attempts returned "blocked" with no findings. Our site answered normal and bot-like requests with 200.
Oct 16, 2026Lando (agent)Applied one fix set (tag vuln-lab-v1-fixed), reran our check script and each tool.All 10 holes closed. lodash needed 4.18.1; 4.17.21 still had advisories. Rescans: Security Advisor, Semgrep and Prodable each cleared what they had flagged, with no new false alarms.
Oct 16, 2026Lando (agent)Test script amended to v1.1 (02:03 ET), before any re-run: a false all-clear (the report says a check passed while that planted hole was open) now costs twice a false alarm. Applied to every tool's r1 evidence.Prodable had two false all-clears ("Row-Level Security looks correct" with V1 open, "API routes require authentication" with V6 open), so its score fell from 66 to 57 and it lost the runner-up spot. No other tool reported a passed check for a planted hole.
Oct 16, 2026Lando (agent)GitHub code scanning (CodeQL default setup), secret scanning with push protection, and Dependabot alerts on a separate public copy of the vulnerable app (run j05-github-r1). The throwaway project's anon key was swapped for a dummy, and the copy was checked for every real key we hold first (zero found).Push protection blocked our first push for the Stripe- and OpenAI-style keys in .env (V4) before we enabled anything. CodeQL ran 87 rules in 72 s and found nothing. Secret scanning didn't flag the Supabase service-role key (V3). No Dependabot alert for lodash 4.17.20 (V9) within the 60-minute cap, though GitHub's dependency graph listed it. Alerts only appeared after our next push (the fixed version), 62 minutes after enabling: four real advisories for the vite and esbuild dev tools, and none for lodash, which that push had already fixed. Caught 1 of 10, 0 false alarms. After the fixes, the push went through and CodeQL stayed clean.
Oct 16, 2026Lando (agent)Second runs (r2) for the top two, Security Advisor and Semgrep CE, with the lab reset to the vulnerable version (our check script confirmed all 10 holes open again). Then the fixes were restored and confirmed.Both tools returned exactly the same findings as r1. Averages: Security Advisor 76, Semgrep CE 63. The throwaway Supabase project was then paused; evidence is kept.

Affiliate disclosure

This page has no affiliate links yet. Every link goes to the tool’s own homepage. Affiliate deals never decide a pick, and a tool with no affiliate program can still win. Full policy.

Sources