Is my Lovable app secure?
Lovable will build the feature you describe, including the database calls. The same speed makes it easy to ship a key or a wide-open table. This page is the short list worth checking before you share the link.
Free check
Check the live app
Paste the public Lovable URL. The check reads what a visitor's browser can already see, then gives you a private report with a fix prompt for each issue.
What Lovable actually ships
Lovable's own FAQ describes the stack. Apps created from May 13, 2026 (June 22, 2026 on Enterprise workspaces) use TanStack Start, which can render pages on the server. Older apps are React and Vite and render in the browser. The database is PostgreSQL, either through Lovable Cloud or a Supabase project you connect. Lovable does not offer a different framework or database. Lovable Cloud is built on Supabase's open-source foundation, so the locks people mean by row-level security still apply.
Mistakes worth checking
These are the ones that show up in apps built with Lovable. Each step is something you can do in the browser or in the product dashboard.
Critical
A service role key in the browser
The Supabase service role key skips every lock, including row-level security. When a query fails with a permission error, the model sometimes reaches for that key so the screen will load. On an older Vite app, a variable that starts with VITE_ is copied into the JavaScript the browser downloads. On a TanStack Start app, the key still leaks if a client component or a public response includes it.
Check it yourself
Open the published app and view the page source. Search for service_role. Then open the browser's developer tools, choose a JavaScript file from your domain, and search again. The anon key is supposed to be there. The service role key is not.
High
Row-level security left off
Lovable Cloud and a connected Supabase project both sit on Postgres. A table with row-level security turned off, or a policy that lets every role read, returns rows to the public anon key. Anyone who loads the page can copy that key. That part is normal. The open table is the problem.
Check it yourself
In Supabase, open each table in the public schema and confirm row-level security is on. Read the policies. An expression that is only true, for the anon or public role, lets a stranger read the table. In Lovable Cloud, use the database view and do the same check. If the live page shows a supabase.co address, request that table while signed out. A real row means the lock is open.
High
A paid API key pasted into a component
A chat that says "add AI" or "add checkout" can drop an OpenAI, Anthropic, or Stripe secret into the client so the demo works today. Stripe's publishable key, the one that starts with pk_, belongs in the browser. A secret key, sk_ or rk_, does not.
Check it yourself
Search the live page and its scripts for sk-, sk_live, sk_test, and rk_. Then search the Lovable project for the same strings outside server-only code.
Medium
A source map that publishes the original files
Vite, which older Lovable apps use, can emit a .map file next to the bundle. That file can include original file names and the original source, comments included. A key you removed from the latest chat can still be sitting in that map.
Check it yourself
In developer tools, open a script from your domain and look for sourceMappingURL. Open that address. If it lists your original files, turn source maps off for the published build and delete the .map files from the host.
Critical
An .env file on a host you copied the app to
Lovable's own hosting is not a public folder of your repo, so this is uncommon on a lovable.app address. It shows up when an older Vite build is exported and the .env file rides along to another host.
Check it yourself
Visit your live domain at /.env and /.env.local. You want a not-found page, not a list of names and values. Rotate anything that was in a file the public could open.
A prompt you can paste
Paste this into Lovable, publish again, and run the check a second time. If a key was already on the live site, rotate it in the vendor dashboard. The prompt cannot do that part.
Review this Lovable app and fix the public security holes in the project. 1. Search client code for a Supabase service_role key, any secret that starts with sk- or sk_live or rk_, a database URL with a password, and a PEM private key. Remove them from client components and from any variable prefixed with VITE_. The anon key may stay in the browser. 2. Move paid API calls, and anything that needs the service role key, into server code: a TanStack server function on a newer app, or an edge function on an older Vite app. Read those secrets from server-only environment variables. 3. Turn on row-level security for every table in the public schema, in Lovable Cloud or in Supabase. Add policies so a signed-in user can only read and write their own rows, unless that table is meant to be public. Do not set a policy to true to silence an error. 4. Turn off production source maps. Do not deploy .env files. 5. List any key that was already in client code so I can rotate it in that vendor's dashboard. Rotating the key is my job, outside this chat. Do not weaken a rule to make a feature load.
What the check looks at
- The public page and the JavaScript it loads, for common leaked secret keys: a Supabase service role key, OpenAI, Anthropic, Stripe secret keys, AWS, GitHub, Slack, private keys, and database URLs that include a password. A Supabase anon key is called out as expected in the browser.
- A short list of public paths: /.env, /.env.local, /.env.production, /.git/config, /.git/HEAD, and /.npmrc.
- A source map, only when a script on the page already points at one, and only when that map includes original source.
- Supabase tables, only when the page already includes a supabase.co address and the public anon key. It asks for one row per table, then drops that row.
- Firebase Realtime Database and Firestore, only when the public config is already in the page. It uses that public config and does not sign in.
- A few browser safety headers on the main response. Missing headers are noted when two or more of the watched ones are absent. They are less urgent than a leaked key.
What stays outside it
- It reads. It does not log in, submit forms, or change data.
- It does not guess passwords, fuzz inputs, or hunt through hidden paths.
- It does not use any secret it finds, including a service role key.
- It does not open your builder's dashboard. A rule that lives only there can stay invisible.
- A clear result describes this public look. It is not a certificate that the whole app is safe.
- If Lovable Cloud does not put a supabase.co address in the published page, the table check cannot see those tables. Confirm row-level security in Lovable Cloud, or in the Supabase dashboard, even when the check looks quiet.
Questions
Free check
Run it on the published URL
Use the address a customer would type. The report stays private, and the shareable scorecard hides the details.
Other builders
- Is my Bolt app secure?Vite variables, Supabase locks, and Bolt Database access you confirm by hand.
- Is my Replit app secure?Secrets in the page, a public Repl, and DATABASE_URL where a visitor can read it.
- Is my Cursor app secure?Client env prefixes, row-level security, Firebase test mode, and source maps.
- Is my v0 app secure?Next.js client bundles, Vercel env vars, and optional Supabase or Neon.
- Is my Base44 app secure?Entity rules you check by hand, plus Vite secrets and service-role calls.
- Is my Windsurf app secure?Agent edits that ship a secret, loosen a database rule, or publish a source map.
- Is my Bubble app secure?Privacy rules, API Connector secrets, and the Data API admin token.