<?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: Muhammed Semri</title>
    <description>The latest articles on DEV Community by Muhammed Semri (@muhammed_semri_d5a477c02b).</description>
    <link>https://dev.to/muhammed_semri_d5a477c02b</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%2F4074961%2Ffdddf2f8-3a1e-4365-ae38-f091a1641573.png</url>
      <title>DEV Community: Muhammed Semri</title>
      <link>https://dev.to/muhammed_semri_d5a477c02b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muhammed_semri_d5a477c02b"/>
    <language>en</language>
    <item>
      <title>I built a Supabase RLS audit that's just SQL wrapped in a prompt</title>
      <dc:creator>Muhammed Semri</dc:creator>
      <pubDate>Thu, 13 Aug 2026 16:15:24 +0000</pubDate>
      <link>https://dev.to/muhammed_semri_d5a477c02b/i-built-a-supabase-rls-audit-thats-just-sql-wrapped-in-a-prompt-1pd5</link>
      <guid>https://dev.to/muhammed_semri_d5a477c02b/i-built-a-supabase-rls-audit-thats-just-sql-wrapped-in-a-prompt-1pd5</guid>
      <description>&lt;p&gt;Every AI coding agent will happily "audit your RLS" if you ask it to. Mine did. It&lt;br&gt;
found three issues, declared the rest fine, and on the second run found two&lt;br&gt;
different issues and declared the rest fine.&lt;/p&gt;

&lt;p&gt;That's the problem. An agent asked to go look enumerates what it happens to&lt;br&gt;
notice, then phrases everything it never checked as an all-clear. The finding&lt;br&gt;
isn't deterministic, so the all-clear is worthless.&lt;/p&gt;

&lt;p&gt;So I inverted it: the prompt doesn't ask the model to investigate anything. It&lt;br&gt;
hands the model the exact SQL, tells it not to substitute its own, and leaves it&lt;br&gt;
doing the one part it's genuinely good at — explaining what a row in the result&lt;br&gt;
means. I put it up at &lt;a href="https://defencecore.com/audit" rel="noopener noreferrer"&gt;defencecore.com/audit&lt;/a&gt; with&lt;br&gt;
no signup wall.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why it's safe to paste into a production database
&lt;/h2&gt;

&lt;p&gt;Every query reads a Postgres &lt;em&gt;catalogue&lt;/em&gt; view — &lt;code&gt;pg_tables&lt;/code&gt;, &lt;code&gt;pg_policies&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;storage.buckets&lt;/code&gt;. Those describe the shape of your database: table names, policy&lt;br&gt;
definitions, bucket settings. There is no statement in the prompt that selects&lt;br&gt;
from an application table, and none that writes.&lt;/p&gt;

&lt;p&gt;That's a property of the SQL, not a promise you're asking a model to keep. You&lt;br&gt;
can read all of it before you paste it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The prompt
&lt;/h2&gt;

&lt;p&gt;You are auditing the Row Level Security configuration of my Supabase project.&lt;/p&gt;

&lt;p&gt;STEP 1 — Run this query exactly as written. Do not modify it, and do not&lt;br&gt;
substitute your own queries. It reads only Postgres catalogue views&lt;br&gt;
(pg_tables, pg_policies, storage.buckets): it cannot read a single row of my&lt;br&gt;
application data, and it changes nothing.&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="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;findings&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'CRITICAL'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="s1"&gt;'Table has no Row Level Security - readable by anyone with the anon key'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;finding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;tablename&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pg_tables&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="n"&gt;rowsecurity&lt;/span&gt;

  &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'CRITICAL'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="s1"&gt;'Policy grants read access to everyone (USING true)'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;tablename&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' -&amp;gt; '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;policyname&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pg_policies&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;qual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;

  &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'HIGH'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="s1"&gt;'Policy accepts any new row (WITH CHECK true) - records can be reassigned'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;tablename&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;' -&amp;gt; '&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;policyname&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pg_policies&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;with_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;

  &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'HIGH'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="s1"&gt;'Storage bucket is public - any object URL downloads without auth'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="k"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buckets&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;

  &lt;span class="k"&gt;union&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt;
  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'REVIEW'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="s1"&gt;'RLS enabled but no policy - table returns nothing to my own app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tablename&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pg_tables&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
  &lt;span class="k"&gt;left&lt;/span&gt; &lt;span class="k"&gt;join&lt;/span&gt; &lt;span class="n"&gt;pg_policies&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
    &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tablename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tablename&lt;/span&gt;
  &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rowsecurity&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;policyname&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;finding&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;findings&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;STEP 2 — Report the results as a table, most severe first, naming the exact&lt;br&gt;
table, policy or bucket. If the query returns no rows, say so plainly instead&lt;br&gt;
of looking for something else to report.&lt;/p&gt;

&lt;p&gt;STEP 3 — For each finding, state in one sentence what someone holding my&lt;br&gt;
public anon key could actually do with it.&lt;/p&gt;

&lt;p&gt;STEP 4 — Describe the fix for each finding in words. Do NOT run, apply, or&lt;br&gt;
offer to run any statement that modifies my database — no ALTER, no CREATE&lt;br&gt;
POLICY, no DROP, no migration. I will make the changes myself.&lt;/p&gt;

&lt;p&gt;STEP 5 — Finally, list which of these findings could silently come back after&lt;br&gt;
a future migration or a future prompt, and explain why a one-time audit cannot&lt;br&gt;
catch that.&lt;/p&gt;

&lt;p&gt;Paste it into Claude Code, Cursor, or anything else connected to your project. No&lt;br&gt;
agent handy? Copy the &lt;code&gt;with findings as (…)&lt;/code&gt; block straight into the Supabase SQL&lt;br&gt;
editor — the SQL &lt;em&gt;is&lt;/em&gt; the audit, the prompt is only the part that reads it back&lt;br&gt;
to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the five checks actually catch
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tables with no RLS.&lt;/strong&gt; Readable by anyone holding your anon key, which ships in&lt;br&gt;
your frontend bundle by design. This is the one everybody knows about and still&lt;br&gt;
the one that shows up most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policies where &lt;code&gt;qual = 'true'&lt;/code&gt;.&lt;/strong&gt; RLS is on, a policy is attached, and it&lt;br&gt;
returns every row to everybody. This passes any audit that only asks &lt;em&gt;is RLS&lt;br&gt;
enabled&lt;/em&gt; — including most dashboard checkmarks and most agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;WITH CHECK (true)&lt;/code&gt;.&lt;/strong&gt; A user can reassign a record they own to somebody else.&lt;br&gt;
Almost always added to silence an insert error, not to deliberately grant&lt;br&gt;
anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public storage buckets.&lt;/strong&gt; Correct for avatars. Wrong for the invoices and&lt;br&gt;
scanned documents that end up in the same bucket because public buckets are where&lt;br&gt;
uploads work on the first try.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RLS on with no policy.&lt;/strong&gt; Not a breach — but it's why a feature quietly returns&lt;br&gt;
an empty list instead of an error, and it's the usual prelude to somebody&lt;br&gt;
disabling RLS to "fix" it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 is the point
&lt;/h2&gt;

&lt;p&gt;The interesting step isn't 1 through 4. It's 5: &lt;em&gt;which of these can come back&lt;br&gt;
silently?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All of them. A migration re-creates a table without its policy. A prompt adds&lt;br&gt;
&lt;code&gt;USING (true)&lt;/code&gt; to unblock a broken query. Someone flips a bucket public to debug&lt;br&gt;
an upload at 1am. Your audit output looks identical the next time you run it,&lt;br&gt;
because you don't run it again.&lt;/p&gt;

&lt;p&gt;That gap is why I ended up building&lt;br&gt;
&lt;a href="https://defencecore.com" rel="noopener noreferrer"&gt;Defencecore&lt;/a&gt; in the first place. A catalogue snapshot&lt;br&gt;
tells you a table is open; it can't tell you who already read it. That's in your&lt;br&gt;
Supabase logs, and on the lower plans those expire in days —&lt;br&gt;
&lt;a href="https://defencecore.com" rel="noopener noreferrer"&gt;Defencecore&lt;/a&gt; reads them as they arrive and keeps the log&lt;br&gt;
lines plus the incident built from them, so the evidence outlives the retention&lt;br&gt;
window that would have deleted it. Read-only, so it can explain a problem and&lt;br&gt;
never cause one.&lt;/p&gt;

&lt;p&gt;Run the prompt first though. It's free, it takes thirty seconds, and roughly&lt;br&gt;
everyone I've handed it to has found at least one &lt;code&gt;REVIEW&lt;/code&gt; row they didn't expect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://defencecore.com/audit" rel="noopener noreferrer"&gt;The audit page →&lt;/a&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>security</category>
      <category>ai</category>
    </item>
    <item>
      <title>Your AI-Built App Passed a Security Scan. Production Is Where the Story Starts.</title>
      <dc:creator>Muhammed Semri</dc:creator>
      <pubDate>Wed, 12 Aug 2026 14:43:54 +0000</pubDate>
      <link>https://dev.to/muhammed_semri_d5a477c02b/your-ai-built-app-passed-a-security-scan-production-is-where-the-story-starts-3np8</link>
      <guid>https://dev.to/muhammed_semri_d5a477c02b/your-ai-built-app-passed-a-security-scan-production-is-where-the-story-starts-3np8</guid>
      <description>&lt;p&gt;AI app builders are adding serious security features.&lt;/p&gt;

&lt;p&gt;That is a very good thing.&lt;/p&gt;

&lt;p&gt;Lovable recently announced AI-powered penetration testing for applications built on its platform. Its existing security tooling already checks areas such as source code, dependencies, secrets, and Row Level Security configuration before an application is published.&lt;/p&gt;

&lt;p&gt;This is an important shift. Security is moving closer to the moment software is generated rather than being treated as something teams add months later.&lt;/p&gt;

&lt;p&gt;But passing a security scan does not mean the security problem is finished.&lt;/p&gt;

&lt;p&gt;It means the application passed a particular assessment at a particular moment.&lt;/p&gt;

&lt;p&gt;Production begins immediately afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  A security scan is a snapshot
&lt;/h2&gt;

&lt;p&gt;Pre-deployment security tools answer valuable questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the code contain a known vulnerability?&lt;/li&gt;
&lt;li&gt;Are dependencies outdated?&lt;/li&gt;
&lt;li&gt;Are database policies missing or overly permissive?&lt;/li&gt;
&lt;li&gt;Is sensitive configuration exposed?&lt;/li&gt;
&lt;li&gt;Can a tester bypass authentication or authorization?&lt;/li&gt;
&lt;li&gt;Is the deployed application vulnerable to common attack techniques?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every team should perform these checks.&lt;/p&gt;

&lt;p&gt;The limitation is time.&lt;/p&gt;

&lt;p&gt;A scan evaluates the application as it exists during the scan. The application will continue changing after that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A coding agent generates another migration.&lt;/li&gt;
&lt;li&gt;A developer temporarily relaxes a policy while debugging.&lt;/li&gt;
&lt;li&gt;A new Edge Function is deployed.&lt;/li&gt;
&lt;li&gt;An integration receives more privileges.&lt;/li&gt;
&lt;li&gt;A secret is accidentally used in the wrong environment.&lt;/li&gt;
&lt;li&gt;Real users begin exercising workflows nobody tested.&lt;/li&gt;
&lt;li&gt;Automated traffic discovers an exposed endpoint.&lt;/li&gt;
&lt;li&gt;A valid account starts behaving in an unexpected way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these changes has to crash the application.&lt;/p&gt;

&lt;p&gt;In fact, many security failures make an application appear to work better.&lt;/p&gt;

&lt;p&gt;Removing a permission check can fix an empty response. Using an administrative key can make a failed request succeed. Making a storage bucket public can fix a broken image. Disabling Row Level Security can make missing rows reappear.&lt;/p&gt;

&lt;p&gt;The feature works.&lt;/p&gt;

&lt;p&gt;The boundary protecting the data no longer does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The production backend is the real security boundary
&lt;/h2&gt;

&lt;p&gt;A modern Supabase application is more than its frontend.&lt;/p&gt;

&lt;p&gt;A project can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication and session handling&lt;/li&gt;
&lt;li&gt;Auto-generated data APIs&lt;/li&gt;
&lt;li&gt;PostgreSQL and Row Level Security&lt;/li&gt;
&lt;li&gt;Storage buckets and object access&lt;/li&gt;
&lt;li&gt;Realtime subscriptions&lt;/li&gt;
&lt;li&gt;Edge Functions&lt;/li&gt;
&lt;li&gt;Service credentials and third-party integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supabase records activity across these services in its platform logs. Those logs provide the production evidence of what the backend is actually doing—not what the code, prompt, or deployment summary says it should be doing. &lt;a href="https://supabase.com/docs/guides/telemetry/logs" rel="noopener noreferrer"&gt;Supabase documents these log sources directly&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That distinction matters for AI-built applications.&lt;/p&gt;

&lt;p&gt;A coding agent can tell you that it implemented authorization. A pull request can show a policy. A test can confirm that one expected request succeeded.&lt;/p&gt;

&lt;p&gt;Production activity answers a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is happening to the application now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That includes legitimate users, automation, developers, coding agents, integrations, misconfigurations, and attackers. Once their actions reach the backend, the backend sees the result without caring which tool generated the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code review, pentesting, and monitoring solve different problems
&lt;/h2&gt;

&lt;p&gt;These security layers are complementary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code and configuration scanning
&lt;/h3&gt;

&lt;p&gt;This examines what has been written.&lt;/p&gt;

&lt;p&gt;It is useful for finding vulnerable dependencies, leaked secrets, dangerous patterns, and incorrect configuration before deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Penetration testing
&lt;/h3&gt;

&lt;p&gt;This actively exercises the application like an attacker.&lt;/p&gt;

&lt;p&gt;It is useful for finding exploitable endpoints, authorization failures, injection paths, exposed data, privilege escalation, and business-logic weaknesses.&lt;/p&gt;

&lt;p&gt;Lovable’s move to make this more accessible is meaningful precisely because “the application builds” and “the application resists attack” are different outcomes. &lt;a href="https://lovable.dev/blog/announcing-pentesting" rel="noopener noreferrer"&gt;Lovable describes that gap in its pentesting announcement&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous production monitoring
&lt;/h3&gt;

&lt;p&gt;This observes what happens after deployment.&lt;/p&gt;

&lt;p&gt;It is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application changes after its last assessment.&lt;/li&gt;
&lt;li&gt;A valid credential is used in an unsafe context.&lt;/li&gt;
&lt;li&gt;Authentication traffic becomes suspicious.&lt;/li&gt;
&lt;li&gt;A data-access boundary changes.&lt;/li&gt;
&lt;li&gt;Production behavior differs from the expected application flow.&lt;/li&gt;
&lt;li&gt;An attacker begins exercising a weakness that was previously unknown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A scan asks, “Can this be exploited?”&lt;/p&gt;

&lt;p&gt;Monitoring asks, “What is happening right now?”&lt;/p&gt;

&lt;p&gt;A production application needs both answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI development loop makes continuous visibility more important
&lt;/h2&gt;

&lt;p&gt;Traditional development usually creates friction between an idea and a production change.&lt;/p&gt;

&lt;p&gt;Someone writes code. Someone reviews it. Tests run. A deployment is prepared. The change reaches production.&lt;/p&gt;

&lt;p&gt;AI coding compresses that loop.&lt;/p&gt;

&lt;p&gt;A developer can describe a feature, approve the result, and deploy it within minutes. That speed is valuable, but it also means security-sensitive changes happen more frequently.&lt;/p&gt;

&lt;p&gt;Consider a common Supabase debugging sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A query returns no rows.&lt;/li&gt;
&lt;li&gt;The coding agent assumes the table or query is incorrect.&lt;/li&gt;
&lt;li&gt;It changes an access policy so the expected data appears.&lt;/li&gt;
&lt;li&gt;The feature starts working.&lt;/li&gt;
&lt;li&gt;The change is deployed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An empty result and a denied result can look similar from the application side. A broader policy may therefore look like a successful fix.&lt;/p&gt;

&lt;p&gt;The agent completed the task it was given. The developer saw the feature work. The application may continue operating normally.&lt;/p&gt;

&lt;p&gt;The security regression becomes visible only when someone deliberately reviews the policy—or when production activity exposes its consequences.&lt;/p&gt;

&lt;p&gt;This is not an argument against coding agents.&lt;/p&gt;

&lt;p&gt;It is an argument for giving fast-moving development teams an independent view of the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Defencecore fits
&lt;/h2&gt;

&lt;p&gt;Defencecore is a continuous security monitor for Supabase applications.&lt;/p&gt;

&lt;p&gt;It connects to a Supabase project with read-only access and watches the platform activity the project already produces across Auth, Postgres, API traffic, Storage, Realtime, and Edge Functions.&lt;/p&gt;

&lt;p&gt;When something requires attention, Defencecore opens an incident that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plain-language explanation&lt;/li&gt;
&lt;li&gt;The affected part of the project&lt;/li&gt;
&lt;li&gt;Relevant production evidence&lt;/li&gt;
&lt;li&gt;A recommended investigation or remediation plan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That plan can be handled manually or passed to a coding agent such as Claude Code or Cursor.&lt;/p&gt;

&lt;p&gt;Defencecore does not modify the database, deploy code, rotate credentials, or automatically rewrite production. Read-only operation is intentional: the system watching production should not have the ability to become the production incident.&lt;/p&gt;

&lt;p&gt;You do not need to instrument every generated feature or depend on a particular AI builder. If the application uses Supabase, the relevant backend activity reaches the same production surface whether the frontend was created with Lovable, Bolt, Replit, Claude Code, Cursor, or by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The security stack for AI-built apps
&lt;/h2&gt;

&lt;p&gt;A sensible workflow now looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate quickly.&lt;/li&gt;
&lt;li&gt;Review security-sensitive code and configuration.&lt;/li&gt;
&lt;li&gt;Scan before publishing.&lt;/li&gt;
&lt;li&gt;Pentest important releases and workflows.&lt;/li&gt;
&lt;li&gt;Monitor the production backend continuously.&lt;/li&gt;
&lt;li&gt;Give developers—or their coding agents—enough evidence to respond safely.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI has dramatically reduced the cost of creating software.&lt;/p&gt;

&lt;p&gt;The next step is reducing the cost of understanding what that software is doing in production.&lt;/p&gt;

&lt;p&gt;That is what we are building at &lt;a href="https://defencecore.com" rel="noopener noreferrer"&gt;Defencecore&lt;/a&gt;.&lt;/p&gt;

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