Our study of 628 apps generated by Lovable and Bolt found that 35.1% of Lovable apps had at least one high-severity finding, against 19.8% for Bolt. Nearly 2x. That kind of gap between two platforms doing roughly the same job demands an explanation, so we went looking for one. This post is what we found.
The numbers behind the gap
The overall difference is driven almost entirely by one finding class: hardcoded credentials. 27.8% of Lovable apps had at least one high-severity hardcoded credential finding, against 13.7% of Bolt apps. Every other finding class was roughly comparable between the two platforms.
And within Lovable's credential findings, one pattern dominates: 59% of Lovable apps with a credential finding had it inside a Supabase client file, almost always at the exact same path. Across the whole Lovable corpus, that is 1 in 6 apps (49 of 299) shipping the same file with the same problem.
| Metric | Bolt | Lovable |
|---|---|---|
| Apps scanned | 329 | 299 |
| Any high-severity finding | 19.8% | 35.1% |
| Hardcoded credential finding | 13.7% | 27.8% |
| Credential finding in a Supabase client file | 4.9% | 16.4% |
Wondering if your code has any of this? Scan a public repo free, no account needed.
Scan a repo →The file
When a Lovable app uses Supabase as its backend, the export contains a file at src/integrations/supabase/client.ts that looks like this (reconstructed; this is the scaffold shape, not code from any specific app):
import { createClient } from "@supabase/supabase-js";
const SUPABASE_URL = "https://yourproject.supabase.co";
const SUPABASE_PUBLISHABLE_KEY = "eyJhbGciOiJIUzI1NiIs...";
export const supabase = createClient(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY);The project URL and the anon key are written directly into source code as string literals. Not read from an environment variable. Not injected at build time. Hardcoded. When the user exports the app to GitHub, the key goes with it, and our scanner flags it as a high-severity hardcoded credential (the anon key is a JWT, which is exactly what the finding title says: “Hardcoded JWT”).
Bolt apps that use Supabase tend to scaffold differently, reading the same values from import.meta.env with a .env file that stays out of git. Same backend, same key, different default, and the difference shows up directly in the two platforms' aggregate numbers.
“But the anon key is supposed to be public”
This is the objection every Supabase-literate developer will raise, and it deserves a straight answer, because it is half right.
Supabase's security model assumes the anon key is visible to the client. It ships in your browser bundle no matter where you store it in your source tree. The thing that makes a visible anon key safe is Row Level Security: permission rules configured on the database itself that control which rows each request can read or write. With RLS correctly configured on every table, someone holding your anon key can only do what your rules allow. Without it, the anon key is a direct line to your entire database. Read every row of every table. Write to any of them.
So the real question is not “is the key visible?” but “is RLS actually configured?” And that is where this pattern turns from a nitpick into a real risk: RLS is a manual step in the Supabase dashboard that nothing forces you to complete. The app works perfectly without it. For someone prompting an app into existence on Lovable, there is no error, no warning, and no visible difference between a locked-down database and a wide-open one, right up until someone else finds the key.
We debated suppressing this pattern in the study the way we suppress other known-public key formats, and decided against it. The key's safety depends entirely on a configuration step we cannot see and the target audience mostly skips. Counting it was the honest call, and we documented the reasoning in the study's methodology section.
How to check your own app in two minutes
- Is the key in your repo? Look for
src/integrations/supabase/client.ts(Lovable) or search your codebase forsupabase.co. If a URL and a longeyJ...string are sitting in a committed file, the key is in your git history even if you remove it later. - Is RLS on? In the Supabase dashboard, open Database, then Tables. Any table without RLS enabled is readable and writable by anyone holding your anon key. Supabase shows a warning badge on unprotected tables; take it seriously.
- Do the policies actually restrict anything? Enabling RLS with a policy like “allow all” is the same as having it off. Each table needs policies that scope reads and writes to the authenticated user who owns the row.
- If your repo is public and RLS was off: rotate the key in the Supabase dashboard (Settings, then API), fix RLS first, and assume the data in unprotected tables may have been read.
The bigger point: scaffold defaults are security decisions
Nobody using Lovable wrote that file. It is generated. Which means this is not a story about careless users; it is a story about how much leverage a platform's template choices have. One default file, repeated across every Supabase-backed export, moved an entire platform's aggregate security posture by double digits in our data. The inverse is also true: changing that one template to read from environment variables would erase most of the measured gap between the two platforms overnight. We would genuinely love to publish that follow-up.
For anyone building on either platform, the takeaway is the same one our whole dataset keeps pointing at: the code that ships from an AI tool is a starting point, and the security-relevant defaults it makes on your behalf deserve at least one pass of human attention before the repo goes public.
Methodology, briefly
All numbers come from the same corpus and scanner run as the main study: 628 apps (329 Bolt, 299 Lovable) sourced from GitHub via structural fingerprints of each platform's export format, scanned with Prbl, with every high-severity finding manually reviewed. No specific repo or finding is identified anywhere in this post; the code sample above is a reconstruction of the scaffold shape, not code from any scanned app. Full methodology, limitations, and the aggregate data CSV are in the main study.