DEV Community

Novruz Veliev
Novruz Veliev

Posted on Originally published at shipclarity.app AI-assisted

What breaks in Lovable apps: data from 190 live apps

Originally published on shipclarity.app.

I ran the same outside-in scan against 190 live apps listed as built with Lovable. No login, nothing a normal visitor's browser could not see. 189 of them had at least one flagged issue. Here is what came up most, what almost never came up, and a two-minute self-check for each.

Aggregate data only: no app names or domains are published, and none will be. The scan ran on 11 September 2026.

The numbers

  • 189 of 190 (99%) had at least one flagged issue (average 4.1, median 4, out of 17 checks)
  • 179 (94%) send no Content-Security-Policy header
  • 172 (91%) send no X-Frame-Options header
  • 150 (79%) answer 200 OK for a page that does not exist
  • 127 (67%) have no DMARC record, or one set to p=none
  • 3 ship a Google/Firebase API key in the bundle; none shipped a Supabase service_role key or a Stripe live secret key
  • 0 exposed a .env, .git or backup file, and 0 of 125 probed Supabase projects returned their schema to the public key

How the data was collected, and what it cannot see

The starting point was a public directory of projects built with Lovable: 512 listings. 428 of them were still live, and 395 of those were in English. After removing portfolios, games, agency pages and pages with no product surface (no pricing, payments, or signup), 190 apps were left, all scanned without errors. 155 run on their own domain; 35 are on a platform subdomain such as *.lovable.app. Some have since moved to Vercel or Netlify, so read this as "built with Lovable", not "hosted by Lovable".

Each app got the same 17 automatic checks that the free ShipClarity scanner runs: exposed config and repo files, secret keys in the JS bundle, Supabase schema exposure to the public key, source maps, SPF, DKIM and DMARC, HTTPS and the HTTP redirect, four security headers, the viewport tag, robots.txt and noindex, the status of a missing page, and first-response time.

What this data cannot tell you

  • The scanner never logs in. Signup, password reset, one user reading another user's rows, checkout and refunds are not measured here.
  • It does not run JavaScript. It reads the server HTML and up to 8 script files referenced from the home page, so a key in a lazily loaded chunk would be missed.
  • Headers are read from the home page only. A CSP set through a <meta> tag is counted as missing.
  • DKIM cannot be confirmed from outside (the selector is provider-specific), so there is no DKIM number here.
  • The sample is a directory of projects whose makers chose to list them, not a random sample of every Lovable app.

1. 189 of 190 had at least one flagged issue

Only one app out of 190 came back clean. The average was 4.1 flagged checks out of 17, the median 4, the worst 8. Most of that count comes from the four items below: configuration defaults nobody revisited, not code bugs. "99% have issues" does not mean 99% are broken for users; it means almost nobody went back over the defaults.

2. 94% send no Content-Security-Policy

179 of 190 apps send no Content-Security-Policy header. CSP tells the browser which scripts may run on your page. Without it, any injected script (a compromised third-party widget, or unescaped user content) runs with full access to the page, including whatever the logged-in user can see.

It is a hosting or proxy setting, not app code, which is why it is missing almost everywhere.

Check yours in 2 minutes

curl -sI https://yourapp.com | grep -i content-security-policy
Enter fullscreen mode Exit fullscreen mode

No output means no header (or check DevTools, Network tab, first request, Response Headers). If your host does not let you set headers, a proxy in front of the domain (Cloudflare, or Netlify/Vercel header rules) can add them. Start with Content-Security-Policy-Report-Only so a strict policy does not break your own scripts on day one.

3. 91% send no X-Frame-Options

172 of 190 apps send no X-Frame-Options header. 171 of them send no CSP either, so there is no frame-ancestors rule covering the gap. Another site can load the app in an invisible iframe and trick a logged-in user into clicking something real: a delete button, a plan change, a share toggle.

From the same family: 44 of 190 (23%) lack X-Content-Type-Options: nosniff, and 23 of 190 (12%) lack HSTS.

Check yours in 2 minutes

curl -sI https://yourapp.com | grep -i -E "x-frame-options|frame-ancestors"
Enter fullscreen mode Exit fullscreen mode

You want X-Frame-Options: DENY (or SAMEORIGIN) or a CSP with frame-ancestors 'none'. frame-ancestors is ignored in a <meta> CSP tag; it only works as a response header.

4. 79% return 200 for a missing page

150 of 190 apps answered 200 OK when asked for a random URL that does not exist. It is the single-page-app default: the host serves index.html for every path and the front-end router decides what to show. Visitors may see "not found", but search engines and uptime monitors see a healthy page.

Search engines may index junk URLs as soft 404s, and monitors keep reporting "up" for deleted routes.

Check yours in 2 minutes

curl -s -o /dev/null -w "%{http_code}\n" https://yourapp.com/this-page-does-not-exist
Enter fullscreen mode Exit fullscreen mode

If it prints 200, open the URL in a browser too: a blank page or the home page is worse than a "not found" screen. The minimum fix is a catch-all route that shows a clear not-found page and adds <meta name="robots" content="noindex">. A real 404 status needs a host-level rule.

5. 67% have no enforcing DMARC

127 of 190 apps have either no DMARC record at all (50) or one set to p=none (77), which blocks nothing. All 127 are on their own domain: 82% of the 155 custom domains. The 35 on a platform subdomain inherit its record. And 52 custom domains (27% of all apps) have no SPF record either.

Without an enforcing policy, anyone can send email as your domain, and your own signup and password-reset emails are more likely to land in spam. For the second part there is a separate guide: Lovable password reset email not arriving.

Check yours in 2 minutes

dig TXT _dmarc.yourdomain.com +short          # macOS / Linux
nslookup -type=TXT _dmarc.yourdomain.com      # Windows
Enter fullscreen mode Exit fullscreen mode

No answer means no record; p=none is monitor-only. The target is p=quarantine or p=reject, but only after SPF and DKIM are set up for the provider that sends your mail, or you will block your own emails.

6. 3 apps ship an API key in the bundle

3 of 190 apps had a key matching a known secret pattern in the JavaScript sent to every visitor. All three were Google/Firebase API keys (AIza...). This type of key is designed to sit in client code and is fine if restricted by HTTP referrer and by API in the Google Cloud console. An unrestricted one can be used on someone else's site at your expense.

The more useful number is the zero: none of the 190 shipped a Supabase service_role key, a Stripe live secret key (sk_live_), or an AWS access key in the scanned bundles, the keys that would hand over the database or the payment account. The Supabase anon key is public by design and was not counted.

Check yours in 2 minutes

In DevTools on your live app, press Ctrl+Shift+F (Cmd+Option+F on a Mac) and search all loaded files for service_role, sk_live_, AKIA and AIza. A hit on the first three means rotate the key now and move the call server-side. A hit on AIza means confirm in Google Cloud Console, Credentials, that the key has both a referrer and an API restriction.

7. What held up

The scary items were rare. Out of 190 apps:

  • 0 exposed a .env, .git/config, config or backup file at a guessable path.
  • 190 load over HTTPS. 3 also still answer on plain HTTP without redirecting.
  • 140 (74%) use Supabase. For 125 of them the scanner could test the public key against the database's REST root, and none returned the schema. The other 15 could not be probed.
  • 3 publish source maps in production, 3 have the home page set to noindex, and 19 (10%) serve no robots.txt.

A closed schema endpoint is a good sign, not a clean bill of health. Whether user A can read user B's rows depends on each table's row-level security, testable only with two real accounts.

Check yours in 2 minutes

curl -s -o /dev/null -w "%{http_code}\n" https://yourapp.com/.env
curl -s -o /dev/null -w "%{http_code}\n" http://yourapp.com/
Enter fullscreen mode Exit fullscreen mode

The first should not be 200 with real file contents (a 200 with your normal app page is the soft 404 from point 4, not a leak). The second should be a 301 or 308 redirect to HTTPS.

What to take from this

Almost everything above is configuration: headers, DNS records, a catch-all route. An afternoon covers it. None of it says whether the app works for a paying user. The failures that cost customers live behind the login: a signup that silently fails, a reset link pointing at the old preview domain, one account seeing another's data, a checkout that charges twice. This dataset cannot say how common those are.

If you want to see where your own app stands, the free outside scanner runs the same 17 checks on your URL in about 20 seconds, with no signup.

Top comments (0)