StackAttestTechnical Trust
Lovable security audit

A Lovable security audit that produces evidence, not reassurance

Lovable gets you to a working application quickly, and the decisions that determine whether it is safe to open to strangers are mostly decisions nobody had to make along the way. This audit establishes which of them are actually right in your application, and records how it knows.

Scan your live appAdd repository validationSee an example Passport

Where the evidence about a Lovable app comes from

Three layers, each answering a different question. Source evidence is where key handling and access rules are read, and runtime is where you find out whether the deployed system agrees with them.

Repository validation

E2
Repository

Reads the source: where secrets live, whether authorisation is enforced on the server or only in the interface, whether data access is injection safe, and which dependencies carry known critical vulnerabilities. Findings cite the file they came from, so a result is checkable rather than asserted.

Runtime validation

E4
Runtime

Builds and runs the application in an isolated environment and probes the running system. This is the layer that answers questions reading code cannot: whether the deployed configuration actually refuses an unauthorised request, and whether error responses leak internals under real conditions.

Public URL scan

E4
URL scan

Tests the deployed application from outside, the way any visitor reaches it: transport security, security response headers, and what the running service discloses about itself. It needs nothing but the address, and what it observes it observes against the running system. Its limit is reach rather than strength: a URL can never establish authorisation, data-layer or backup posture, and those controls stay uncovered.

Where this architecture concentrates risk

A Lovable project usually has a Postgres backend with row level security in front of it, and these are the places that arrangement is most often left unfinished. They are not claims about your application. The audit exists to establish which of them are present in yours, and which are not.

Table policies that stop at whether you are signed in

Row level security is only as good as the predicate inside each policy. A policy that permits any authenticated role is a policy that lets every signed-in customer read the whole table, and it looks identical to a correct one while you are the only account in the database. The question is not whether policies exist. It is whether each one names the column that ties a row to its owner.

The two keys, and why only one of them is an exposure

The publishable key is designed to sit in the browser. It is how the client talks to the backend at all, and with correct policies it is safe there, because the policies are what decide what it can read. The service role key is a different object: it bypasses every policy by design. In a bundle, a committed env file, or an error response, that key is a serious exposure and rotating it is the first thing to do. Flagging both as vulnerabilities is how the one that matters gets lost in the noise.

Storage buckets with looser rules than the tables

Object storage carries its own access rules, separate from the table policies, and a bucket is often opened during development so images render. Uploads are frequently the most sensitive thing in the product: identity documents, invoices, anything a user attached. A correct table policy does not constrain a public bucket.

Server functions that act on an identifier they were handed

Edge functions are the point where the client and server boundary is actually drawn. A function that takes a record identifier from the request and acts on it, or that runs with the privileged key and therefore skips the policies entirely, moves the ownership check to a place where nobody is performing it.

Rules enforced in the browser because that is where the work happened

Validation and permission logic drift into client code because that is where the generated screens live. Anything enforced only there is advisory: the client is under the caller's control, and a direct request to the backend never runs it.

The second customer changes the question

The moment there is a second customer the question changes from whether the application works to whether account A can reach account B. That is a different test, it is not answered by reading policy definitions, and it is the failure that costs the most when it turns out to be real.

What the result looks like

An illustrative extract, not a real customer result. Every row carries the evidence grade behind it, and a control nobody could establish says so.

ControlStatusEvidenceNote
Object ownership enforced server-sideFailedE4A second account's rows returned to a signed-in caller
Secrets managed outside source codeVerifiedE2No key that bypasses table policies reachable from client code
Server-side input validation on state-changing endpointsPartialE4Two server functions accepted an unchecked body under probe
Injection-safe data accessVerifiedE2Generated data access is parameterised throughout
Database queries are index-backed at scaleUncoveredNot gradedNo schema evidence available from the layers that ran

Mapped to published standards

Each control is tested against a named clause, so a result means something outside our own vocabulary. Mapping is not certification, and none of these bodies endorse StackAttest.

OWASP ASVS 5OWASP API Security Top 10OWASP WSTGCWENIST SSDF

What this audit is not

  • It is not a penetration test. A deterministic check and a runtime probe are not an adversarial human engagement, and there are classes of weakness only a person hunting for them will find.
  • It is not SOC 2 and does not replace it. SOC 2 attests to organisational controls over time; this validates technical controls in the software. They answer different questions for different buyers.
  • It does not replace human due diligence. It gives a reviewer repeatable evidence to start from, which is a different thing from being the reviewer.
  • Controls the run could not reach are reported as uncovered rather than passed. A result you did not earn is worse than no result.
  • It covers thirteen defined controls, which is a floor rather than a complete security review. Business rules that are wrong in a way only you would recognise sit outside it, and the report names what was in scope instead of implying everything was.
  • It is not affiliated with Lovable or Supabase and does not integrate with either. It validates the application that was produced, from the address you give it and, if you connect one, the repository.

Questions

What is a Lovable security audit?

An independent check of an application built with Lovable, testing named technical controls against published standards rather than reading the code for style. Each result records how strong the evidence behind it is, and any control the run could not reach is listed as uncovered instead of passed.

Is my Lovable app insecure?

Nobody who has not tested it knows, and we are not going to assert it to sell you something. The failure modes on this page are common in this architecture, which is a very different statement from every Lovable project having them. The audit exists to establish what is true of yours.

Is the publishable key in my browser bundle a vulnerability?

No. That key belongs in the browser and is meant to be visible; it is how the client reaches the backend at all, and your table policies are what decide what it can do. The credential that must never appear in client code is the service role key, because it bypasses those policies. If you find one in a bundle, rotate it before anything else.

Do you integrate with Lovable or Supabase?

No. There is no plugin, no connector and nothing to authorise in either product. We validate the software that was produced: the deployed application at the address you give us, and the repository if you choose to connect one read-only.

Can you tell me whether one customer can read another customer's rows?

That is what runtime validation exists for. Reading a policy tells you what should happen; probing the running system establishes what does. Where a run cannot reach that behaviour, the control is reported as uncovered rather than assumed to pass.

How is this different from your guide on checking a Lovable app?

The guide walks you through the same questions so you can answer them yourself, and it stays free of pricing on purpose. This is the version we run: the same controls, tested independently, ending in graded evidence and a Passport you can publish. Use the guide if you want to do the work. Come here if you need a result that convinces someone who does not take your word for it.

Related

Is my Lovable app secure?Cursor security auditVibe code auditAI app security auditSecurity and data handling

Find out what is actually true of your application

Start with the layer you can run today. The report says which layers ran and what they could not reach, so the result is honest about its own limits.

Scan your live appAdd repository validation