<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: FlawPilot</title>
    <description>The latest articles on DEV Community by FlawPilot (@flawpilot).</description>
    <link>https://dev.to/flawpilot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4062116%2F65b712d3-54d2-4489-a0c5-e024c9d1baaf.png</url>
      <title>DEV Community: FlawPilot</title>
      <link>https://dev.to/flawpilot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flawpilot"/>
    <language>en</language>
    <item>
      <title>Lovable App Security We Scanned a Real App and Found 29 Open Issues</title>
      <dc:creator>FlawPilot</dc:creator>
      <pubDate>Fri, 14 Aug 2026 12:29:29 +0000</pubDate>
      <link>https://dev.to/flawpilot/lovable-app-security-we-scanned-a-real-app-and-found-29-open-issues-4hj1</link>
      <guid>https://dev.to/flawpilot/lovable-app-security-we-scanned-a-real-app-and-found-29-open-issues-4hj1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxcmt6hej70ia942uz9gr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxcmt6hej70ia942uz9gr.png" alt=" " width="800" height="521"&gt;&lt;/a&gt;Quick answer: Lovable app security's most common failure isn't a missing header. It's an unset Supabase Row-Level Security policy. Skip it and the app still works, because the query still succeeds, just for anyone, not only its owner. We scanned a real Lovable app and found exactly that gap, live.&lt;/p&gt;

&lt;p&gt;Picture the app you shipped last sprint. You described a dashboard, Lovable wired up the tables, the auth, the UI, and it all just worked the first time you clicked through it. That's the whole appeal. It's also exactly why nobody goes back and checks the one setting that doesn't announce itself when it's missing. So we did. We took a real, live Lovable app, built the way most Lovable apps get built (fast, from a prompt, shipped the same week), and ran it through &lt;a href="https://flawpilot.com?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;FlawPilot&lt;/a&gt;, a free scan that checks a site's &lt;a href="https://flawpilot.com/use-cases/security?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;security&lt;/a&gt;, &lt;a href="https://flawpilot.com/use-cases/performance?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;performance&lt;/a&gt;, &lt;a href="https://flawpilot.com/use-cases/infrastructure?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;infrastructure&lt;/a&gt;, and &lt;a href="https://flawpilot.com/use-cases/seo?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;SEO&lt;/a&gt; in about two minutes, no login required. We won't name the app, but every number below is real, pulled straight from its report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scorecard
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;63 out of 100. "At risk."&lt;/strong&gt; 252 points out of a possible 400, and 29 things sitting open: 1 critical, 5 high, 15 medium, 8 low.&lt;/p&gt;

&lt;p&gt;Split out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security: 55/100.&lt;/strong&gt; At risk. 13 findings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance: 96/100.&lt;/strong&gt; Excellent. 2 findings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure: 58/100.&lt;/strong&gt; At risk. 9 findings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO &amp;amp; Discoverability: 62/100.&lt;/strong&gt; Needs attention. 5 findings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing was defaced. The app looked, and behaved, exactly like it was supposed to. That's the part worth sitting with: every screen worked, every click did the right thing, and the one critical finding on this report had never once shown up as a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it got right
&lt;/h2&gt;

&lt;p&gt;96/100 on performance is close to a clean sweep. Lovable's scaffolding leans on Vite and React defaults that are already fast out of the box: quick first paint, sensible bundle size, nothing render-blocking that shouldn't be.&lt;/p&gt;

&lt;p&gt;Which is exactly the trap. A fast, polished frontend is the thing you notice with your own eyes, so it's the thing that gets credited as "done." Everything below is the kind of gap that only shows up once something outside the team, a scanner, a bot, or someone who isn't supposed to, goes looking for it on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was hiding underneath
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A Supabase table had no Row-Level Security policy at all.&lt;/strong&gt; Rated Critical, and it's the finding that matters most on this whole report. Lovable apps run on Supabase by default, and Supabase enforces access at the database layer through RLS policies, not through the app's own login screen. Turn RLS on for a table and the database itself checks who's allowed to see which row. Leave it off, and the table is exactly as open as the &lt;code&gt;anon&lt;/code&gt; key that ships in every Lovable app's JS bundle: open to anyone who opens dev tools and watches a single network request. This app's login screen worked correctly the whole time. The database behind it never checked whether the person asking was allowed to see the data they were asking for.&lt;/p&gt;

&lt;p&gt;The fix, in Supabase, is two SQL statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Enable Row-Level Security on the table&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;ENABLE&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="k"&gt;LEVEL&lt;/span&gt; &lt;span class="k"&gt;SECURITY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Scope reads to the row's own owner&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"Users can view their own orders"&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No rewrite, no data migration, just a policy that tells the database who's allowed to see which row instead of trusting the app's UI to gate it for you. Repeat per table, per operation (&lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;) as needed.&lt;/p&gt;

&lt;p&gt;The rest of the report was more familiar territory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No DMARC record&lt;/strong&gt;: anyone could send email pretending to be this domain (High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;Content-Security-Policy&lt;/code&gt; header&lt;/strong&gt;: an injected script has nowhere to be stopped (High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header&lt;/strong&gt;: first request can get downgraded to plain HTTP (High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No clickjacking protection&lt;/strong&gt;: the app can be framed invisibly inside another page (High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No CAA record&lt;/strong&gt;: any certificate authority could issue a cert for the domain (Medium)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No DKIM signature&lt;/strong&gt;: outgoing mail at real risk of landing in spam (Medium)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing &lt;code&gt;sitemap.xml&lt;/code&gt;, thin meta descriptions&lt;/strong&gt;: dragged the SEO score to 62 (Medium)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verbose error pages left on&lt;/strong&gt;: handing back stack traces to anyone who triggers one (Medium)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this showed up while clicking through the app. All of it shows up the moment something outside the team, a scanner, a bot, an attacker, bothers to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is the default, not a fluke
&lt;/h2&gt;

&lt;p&gt;That combination, an unset RLS policy sitting next to missing headers and no DMARC, is close to the single most repeated pattern across Lovable apps specifically. Lovable isn't careless, it's optimizing for "the prompt works," and a Supabase table without an RLS policy still returns exactly the data you asked for in testing. The query succeeds either way. Nothing about that failure looks like a failure until someone sends a request the app wasn't expecting.&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. In March 2025, this exact gap, missing RLS in Lovable-generated apps, was catalogued as &lt;strong&gt;CVE-2025-48757&lt;/strong&gt; (CVSS base score 8.26, High), and left more than 170 live production apps with databases any unauthenticated visitor could read, write to, or delete from, just by inspecting the app's own network requests. Nobody shipped a bug that broke anything. The gap was a security control nobody had reason to think about, sitting quietly under apps that worked perfectly for months.&lt;/p&gt;

&lt;p&gt;The broader research backs this up. Veracode's GenAI Code Security testing has run over 100 models across 80 coding tasks over four years, and the average pass rate on a security review has held at roughly 56%, meaning close to 44% of AI-generated code fails a review outright. A 2023 Stanford study (Perry et al., ACM CCS) found the same pattern at the human level: developers using an AI coding assistant wrote measurably less secure code than developers working without one, and felt &lt;em&gt;more&lt;/em&gt; confident about it, not less. The role that used to catch an unset RLS policy, a senior engineer flagging it in code review, mostly doesn't exist in a Lovable workflow, because there's often no review step between describing the app and the app going live.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually fix this
&lt;/h2&gt;

&lt;p&gt;A severity label is only useful if it turns into something you actually do. Here's how FlawPilot handles that on this exact report.&lt;/p&gt;

&lt;p&gt;Every finding gets grouped by area and dropped into a ranked &lt;strong&gt;"What to do next"&lt;/strong&gt; list, not a raw dump of jargon. Item one was the RLS finding, and next to it, in plain English: &lt;em&gt;enable Row-Level Security on this table and add a policy scoping rows to the authenticated user.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Four of the five High findings here (CSP, HSTS, clickjacking, DMARC) are pure configuration, no application logic involved. The RLS fix is a Supabase policy, not a rewrite. Clear those five and close out the CAA and DKIM gaps next to them, and a security score that opened at 55 is realistically headed for the 90s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on your own app
&lt;/h2&gt;

&lt;p&gt;No setup, no coding, no passwords required. Drop in a URL, and in about two minutes you get a full scorecard: security, performance, infrastructure, and SEO, each out of 100, every finding in plain English, with a toggle between a plain-language view and the full technical one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://flawpilot.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-app-security" rel="noopener noreferrer"&gt;Scan your Lovable app for free →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Lovable secure by default?&lt;/strong&gt;&lt;br&gt;
Not fully. Lovable handles HTTPS and gets you a working auth flow fast, but Row-Level Security on your Supabase tables is opt-in, and HTTP security headers, DMARC, and DNS hardening aren't configured automatically either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the single most common Lovable security issue?&lt;/strong&gt;&lt;br&gt;
A Supabase table with no Row-Level Security policy, also the most severe, since it can leave underlying data readable or writable by anyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does scanning my site give FlawPilot access to my Supabase project?&lt;/strong&gt;&lt;br&gt;
No. The scan only checks publicly accessible signals, the same things any browser or bot on the internet can already see. It never touches your Supabase dashboard, your database directly, or your credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I fix this myself without hiring anyone?&lt;/strong&gt;&lt;br&gt;
Header, DNS, and email-authentication fixes usually live in your hosting or DNS provider's dashboard. The RLS fix lives in your Supabase project's SQL editor or policy UI and takes minutes once you know which table needs it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I actually check this?&lt;/strong&gt;&lt;br&gt;
Before anything you'd call a real release, and again any time you add a new table, since a new table means RLS is opt-in again.&lt;/p&gt;




&lt;p&gt;The app worked the whole time. The database behind it never once did. That gap is the part worth remembering long after the specific header names and CVE numbers fade: "it works" and "it's secure" get checked by two different questions, and only one of them shows up on screen.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>supabase</category>
      <category>security</category>
    </item>
  </channel>
</rss>
