Skip to content

Security basics

Lovable security scan: the one thing it cannot prove

Lovable security scan: what the Quick and Deep scans check, when each one runs, and the one thing no scan from inside your project can prove.

Vlad Tkachenko10 min read
A report panel with a column of ticks on it, and behind it, running off the edge of the frame, a database with rows drifting out.

In short

  • The Lovable security scan is really two scans, both free: a Quick one that runs by itself every time you publish, and a Deep one you start yourself that reads all your application code.
  • Both read your project from the inside. Neither makes the request a stranger makes, so neither can prove what your published app hands back.
  • Of the 3,553 Lovable apps whose Supabase database we could ask from outside, 2,017 answered a request with no login. Run the inside scan before you publish and an outside one after.

You click Publish on your Lovable app and a scan runs before it goes out. A few seconds later it comes back clean, or it comes back with a list, and either way you are holding a result you have no way to judge. Is that everything? Is it enough to put real people on this?

Here is the part worth knowing before you decide: the Lovable security scan and a scan of your published app are reading two different objects. One reads the locks and the wiring. The other walks up and pulls the handle. Both are worth doing, and only the second one does what every visitor to your app does all day.

Does Lovable scan my app for security problems?

Yes, and there are two of them. Both are free.

The Quick scan runs by itself every time you publish and finishes in seconds. The Deep scan reads all of your application code and you start it yourself. Both of them read your project from the inside: your database settings, the access rules on your tables, your dependency tree, your code.

Everything below was read off Lovable's own security documentation on 24 September 2026. This feature has changed more than once in a year, so check the date on any article describing it, including this one.

Two scans, two places to stand. The one inside the box can open anything in the project. The one in the street can only ask the app what it hands over, which is the same thing the three people beside it are doing.

What the Lovable security scan checks

Three areas, in a fixed set of checks, in seconds, on every publish.

Lovable's documentation lists them as a database review, a dependency audit and an MCP server check. The database review is the one that matters most to this article, and their wording for it is worth reading closely: it covers "tables without per-record access control (row-level security), access rules that let everyone through, and leaked-password protection turned off". The dependency audit looks for known vulnerabilities in your npm packages. The MCP check looks for an MCP server your app exposes without authentication.

Findings come back grouped by area and labelled Critical, Warning or Info. The scan fires automatically from the publish dialog, and you can also start it from the project Security view.

Some write-ups call this the Basic scan. The control in the Security view today reads Run quick scan, so if an article and your screen disagree on the name, your screen is the current one.

What the Deep scan adds

It reads all of your application code, and it does not start itself.

The Deep scan includes everything in the Quick scan and then looks at your own logic, permissions and data. Lovable lists seven areas: access control and authorization, unauthenticated and abusable endpoints, unsafe input and injection, leaked secrets and credentials, payments and billing, authentication and account security, and exposed personal and sensitive data. It is free too.

The sentence in the docs to actually act on is this one: the Deep scan does not run automatically as you work. It runs when you run it. A project that has never had one has never had its code read, no matter how many times it has been published, and the publish dialog will not tell you that. Enterprise workspaces can schedule Deep scans across selected projects from the workspace Security center, which is the one arrangement where it happens without somebody remembering.

Lovable can also attempt fixes, either while you build or through Try to fix all in the Security view. Read what a fix changed before you accept it. The repair that makes a row-level-security error go away is very often a policy that permits everybody, and that policy satisfies the check while leaving the table open.

The 2025 complaint, and what changed

The first version of this check told you a policy existed. It did not tell you the policy worked, and the researcher who found the original problem said so at the time.

In May 2025 Matt Palmer published CVE-2025-48757, covering Lovable apps whose Supabase tables had row-level security missing or written too permissively. Lovable's response was the pre-publish check. Palmer's own write-up described its limit in one parenthesis:

Lovable's Publish feature will help ensure that RLS policies are enabled in all tables and notify if they aren't (but doesn't necessarily indicate if they are sufficient).

That gap has an answer in the current documentation, which names "access rules that let everyone through" as something the database review flags. Nothing in this article tests that claim. If you want it tested, add a throwaway table with a policy that permits everybody and see whether the scan names it. The longer version of the CVE is in is Lovable safe.

What a scan from the inside cannot prove

Whether your live app hands rows to somebody who is not logged in.

A lock can be fitted, listed and correct on the drawing, and the door still opens. A policy is a statement about what should happen; the thing that settles what does happen is a request. Three ways a rule reads as present and the table still answers:

  • The policy permits everybody. Written as using (true), it is a valid policy, it satisfies the requirement that one exist, and it returns every row to every caller.
  • The policy covers reads and nothing else. Selecting is checked, inserting and updating and deleting were never written, so anyone can write to a table nobody can fully read.
  • The condition matches more people than it was meant for. It was supposed to name one customer and it names every signed-in visitor, or every visitor.

Now the part that decides how you should read a green result. From outside, those three and a table with no protection at all give the same answer, which is rows. Your users cannot tell them apart. Neither can anybody else who opens your app.

The request that settles it, and the rows it came back with. The project sits under the page and touches the line nowhere, which is why nothing inside it can answer for what happened here.

Between 12 and 14 August 2026 we ran the same nine external checks over 30,998 live apps, and 18,554 of them were published on Lovable. Of the Lovable apps that named a Supabase project, 3,553 answered us clearly enough to judge, and 2,017 of those handed back rows to a request carrying no login at all. The method and every denominator are in the report.

One honesty rail on that number. We stood on the pavement, and we have no view inside any of those projects. We can report what 2,017 published apps answered. We cannot report how many of them had run a scan, or what it told them.

Your own app answers the same question in about 20 seconds, and you do not have to take our word for which side of the 2,017 it falls on: scan your app. It asks each table for a count of the rows a caller with no login would be given, reads the number, and stops there without fetching a row.

What an outside scan cannot see

Pulling the handle tells you nothing about a room with no door onto the street, and there are four of those.

Your npm dependency tree is not in the page a browser downloads. Your server-side code, including edge functions and whether a route checks who is calling, runs somewhere we never reach. A table your front end never names is invisible to us, because we find table names in the code your app ships plus a short list of common ones, so a table nothing in the browser touches and nobody would guess does not get asked. And an MCP server is not something a page request finds.

Lovable's two scans between them read all four. Ours prints "Couldn't check" when it could not answer a question, rather than a tick.

What it isLovable's scan, insideAn outside scan
Row-level security switched off on a tableYesOnly by its effect
A policy that lets everyone throughYes, per its docsYes, by the rows it gets
What your published app hands a strangerNoYes, this is the whole job
Your npm dependenciesYesNo
Server-side code and edge function authenticationYesNo
A table your front end never namesYesNo
Which key ended up in the code visitors downloadYesYes
Your certificate date, domain date and page headersNot in its listYes

The row about what your published app hands a stranger is the reason to run both, and it is the row our scan was built around. The general version of where an outside view stops is what a URL scan misses.

Run both, in this order

The inside scan before you publish, the outside one after, because that is the order the two things happen in.

  1. Let the Quick scan run at publish, then read it. It is a few seconds and it is already happening. Clicking past the dialog is the commonest way a Critical finding reaches production.
  2. Run a Deep scan before anything real goes live, and again after you add sign-in, payments, or any table that holds people. It will not run itself.
  3. Publish.
  4. Scan the published address from outside. Ours reads your live app the way a visitor does, takes about 20 seconds, needs no account, and names the checks it could not finish: scan your app.

There is a gap in that sequence, and it is the one worth planning around. The Quick scan runs when you publish. Most of what opens a table does not go through publish at all: you change a setting in the Supabase dashboard, you accept a policy an assistant wrote in a chat window at midnight, you add a table this morning and the screen that reads it ships on Thursday. None of that is a publish, so none of it starts a scan, and the Deep scan was never going to run on its own anyway.

Every publish starts a scan. A setting changed in the Supabase dashboard is not a publish, and the amber carries on past the next one, because that scan reads the project rather than the table.

Reeve Monitor runs the outside half on the days you do not think to. It re-runs all nine checks every hour on up to three apps, watches whether your app is answering at all, tells you when a result changes instead of waiting for you to come and look, and sends a report at the end of each month.

Reading a green scan

A clean result means every question that scan could ask came back clean on the day you ran it. That is worth having and it is not a verdict on your app.

Lovable puts the same caveat in its own docs: the tools help identify common security issues and cannot guarantee complete security. Ours carries it too, because an automated external check is not an audit and an empty findings list is not a guarantee.

The one rule to keep for when the two disagree: if the inside scan is clean and an outside scan says a table answered a request with no login, act on the outside answer. It is the answer your users get, and it is the answer anybody else gets as well. Go and read the policy on that table.

If your app is on Supabase, the plain-language walkthrough for this platform is is your Lovable app safe, and the checks written out as commands you can run yourself are in the Supabase security checker.

What to do this week

What to do

  • Read the Quick scan result at publish instead of clicking past it, and treat a Critical label as something to fix before the app goes out.
  • Run a Deep scan by hand. It does not start on its own, so a project that has never had one has never had its code read.
  • After publishing, scan the live address from outside. That is the only check that makes the request a stranger makes.
  • Read the policy on every table that holds people. One that permits everybody leaves the table open while the dashboard reports it as protected.
  • Check that the key in your app is the publishable one. Which API keys are safe in your frontend is how to tell the two apart.
  • When the inside and outside answers disagree, the outside one is what your users get.

If your Lovable app uses Supabase, open a private browsing window and go through the list under Authentication and Policies before Friday. Can anyone read your Supabase database is the same test written out as commands you can paste into a terminal.

FAQ

Does Lovable scan my app for security problems?

Yes, and there are two scans. The Quick scan runs by itself every time you publish and finishes in seconds, covering your database access rules, your npm dependencies and any MCP server your app exposes without authentication. The Deep scan reads all of your application code and you have to start it yourself from the project Security view. Both are free, and both read your project rather than your published app.

What is the difference between the Quick scan and the Deep scan?

Speed and depth. The Quick scan runs a fixed set of checks in seconds, automatically at publish, and covers your database settings, your dependencies and MCP exposure. The Deep scan includes everything in the Quick scan and then reads your application code for problems specific to your own logic and data: access control, unauthenticated endpoints, injection, leaked secrets, payments, account security and exposed personal data. The Deep scan does not run on its own as you work, so a project that has never had one run has never had its code read.

Is Lovable's security scan enough?

It is a real check and it sees things no outside tool can, such as your dependency tree and a table your front end never names. What it cannot do is make the request your visitors make. A policy can exist, read as valid and still return every row, and the only thing that settles which of those you have is asking your published app from outside with no login. Lovable says the same in its own documentation: the tools help identify common security issues and cannot guarantee complete security.

Why does an external scanner find things Lovable's scan passed?

Because the two read different objects. An inside scan reads your project: the schema, the policies, the dependency tree, the code. An outside scan reads what the published app hands a stranger who is not logged in. From outside, a table with no protection at all and a table with a policy that permits everybody give the same answer, which is rows. That answer is the one your users and everybody else actually get, so when the two disagree it is the one to act on.

Do I need both?

They answer different questions, so running one does not stand in for the other. The useful order is the order the two things happen in: let the Quick scan run at publish, run a Deep scan before anything real goes live and after you add sign-in, payments or a table holding people, then scan the published address from outside. An outside scan takes about 20 seconds and needs no account.

Written by

Vlad Tkachenko

Founder, Reeve

I spend my time looking at apps built with Lovable, Bolt, v0, Cursor and Replit, and at the short list of mistakes that keep turning up in them.

More about the author

Read next

All articles

Not sure where your own app stands?

Run a free scan and get a plain-language grade from A to F in about 20 seconds. No account, no card.

Scan your app free

Automated external check, not a full audit. Absence of findings is not a guarantee of safety.