<?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>Before You Deploy an AI-Built Website: A Developer's Launch Review</title>
      <dc:creator>FlawPilot</dc:creator>
      <pubDate>Fri, 09 Oct 2026 07:55:15 +0000</pubDate>
      <link>https://dev.to/flawpilot/before-you-deploy-an-ai-built-website-a-developers-launch-review-487i</link>
      <guid>https://dev.to/flawpilot/before-you-deploy-an-ai-built-website-a-developers-launch-review-487i</guid>
      <description>&lt;p&gt;AI coding tools can take a prompt to a working UI in an afternoon. The preview looks finished, the happy path works, and it is tempting to ship.&lt;/p&gt;

&lt;p&gt;But a preview proves one thing: the intended path works in one controlled environment. It says nothing about whether user A can read user B's data, whether a key is sitting in your JavaScript bundle, or whether staging's &lt;code&gt;noindex&lt;/code&gt; made it to production.&lt;/p&gt;

&lt;p&gt;This is the review we run before deploying generated code. It is not a threat model, pen test, or compliance audit. It is a way to catch the common launch gaps while they are still cheap to fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Block the release if any of these is true:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;A real secret reaches the browser or the repo history.&lt;/li&gt;
&lt;li&gt;A normal user can reach another user's data or an admin action.&lt;/li&gt;
&lt;li&gt;The core journey (signup, checkout, form) fails on the production URL.&lt;/li&gt;
&lt;li&gt;Production inherited a staging restriction (&lt;code&gt;noindex&lt;/code&gt;, wrong canonical, password wall).&lt;/li&gt;
&lt;li&gt;Nobody can roll back or knows who is watching after launch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Everything below is how to check these quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Test the deployed journey, not the generated screens
&lt;/h2&gt;

&lt;p&gt;Run the review against the production URL or an environment that mirrors it. Preview builds often differ in caching, asset paths, env vars, and domains.&lt;/p&gt;

&lt;p&gt;Pick the one action the site exists for (contact form, signup, checkout, upload) and complete it end to end. A success toast is not proof. Confirm the data arrived, the email was delivered, and the right system received it.&lt;/p&gt;

&lt;p&gt;Then break it on purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit empty and malformed values&lt;/li&gt;
&lt;li&gt;Reuse an expired token or old confirmation link&lt;/li&gt;
&lt;li&gt;Reload mid-flow, then use the back button after completion&lt;/li&gt;
&lt;li&gt;Upload a blocked or oversized file&lt;/li&gt;
&lt;li&gt;Cancel or fail a payment in test mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A failure should be clear and safe. It should never leak stack traces, internal paths, database errors, or tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Test authentication and authorization separately
&lt;/h2&gt;

&lt;p&gt;Authentication answers "who are you?" Authorization answers "what may you do?" A working login only proves the first.&lt;/p&gt;

&lt;p&gt;Create at least two users with different roles, then try to cross the boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Logged in as user A, request a record owned by user B&lt;/span&gt;
curl &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="se"&gt;\_&lt;/span&gt;&lt;span class="s2"&gt;A"&lt;/span&gt; &lt;span class="se"&gt;\\&lt;/span&gt;
  https://example.com/api/invoices/&amp;lt;ID&lt;span class="se"&gt;\_&lt;/span&gt;OWNED&lt;span class="se"&gt;\_&lt;/span&gt;BY&lt;span class="se"&gt;\_&lt;/span&gt;B&amp;gt;

&lt;span class="c"&gt;# Expect 403 or 404. A 200 means broken access control.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also try an admin endpoint as a normal user, change a role value in a request body, and attempt a write with a read-only account.&lt;/p&gt;

&lt;p&gt;Hiding a button in the UI does nothing if the endpoint is open. Enforce ownership on the server, in the query itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/invoices/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requireAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findFirst&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ownerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-tenant apps need extra care: a user from one organization must not be able to read, search, or infer another organization's data.&lt;/p&gt;

&lt;p&gt;Broken access control sits at the top of the &lt;a href="https://owasp.org/Top10/" rel="noopener noreferrer"&gt;OWASP Top 10&lt;/a&gt;, and generated code is a common place for it to hide.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Trace every secret from source to browser
&lt;/h2&gt;

&lt;p&gt;If a value reaches the browser, assume anyone can read it. Frameworks differ on which env vars are bundled into client code, and generated examples do not always say.&lt;/p&gt;

&lt;p&gt;Search your production build output, not just your source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Adjust the build folder for your framework (dist, build, .next/static, out)&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rEn&lt;/span&gt; &lt;span class="s2"&gt;"sk&lt;/span&gt;&lt;span class="se"&gt;\_&lt;/span&gt;&lt;span class="s2"&gt;live|AKIA&lt;/span&gt;&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="s2"&gt;0-9A-Z]{16}|api&lt;/span&gt;&lt;span class="se"&gt;\[\_&lt;/span&gt;&lt;span class="s2"&gt;-]?key|secret"&lt;/span&gt; dist/ 2&amp;gt;/dev/null

&lt;span class="c"&gt;# Source maps can expose original code&lt;/span&gt;
find dist &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\*&lt;/span&gt;&lt;span class="s2"&gt;.map"&lt;/span&gt;

&lt;span class="c"&gt;# Was a key ever committed?&lt;/span&gt;
git log &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt;&lt;span class="s2"&gt;"sk&lt;/span&gt;&lt;span class="se"&gt;\_&lt;/span&gt;&lt;span class="s2"&gt;live"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also review network requests in DevTools, build logs, error messages, and example config files.&lt;/p&gt;

&lt;p&gt;If a real credential was exposed, rotate or revoke it. Deleting it from the latest commit does not remove it from Git history, caches, logs, or deployment artifacts. Give each key the minimum permissions it needs and restrict it by origin, environment, or quota where the provider allows.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Prune dependencies and third-party scripts
&lt;/h2&gt;

&lt;p&gt;Generated projects collect packages and scripts across prompts, and some outlive the feature that needed them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
npx depcheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove what is unused, review what is left, and apply upgrades in a branch with tests and a rollback path. Do not bulk-upgrade right before release.&lt;/p&gt;

&lt;p&gt;For every third-party script on the deployed page (analytics, chat, ads, widgets), know who owns it, why it is there, and what data it receives.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Inspect the real production response
&lt;/h2&gt;

&lt;p&gt;Your hosting platform, CDN, or proxy can change what the browser actually receives. Look at the live response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Headers on the final response&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com

&lt;span class="c"&gt;# Redirect chain: http, www, and non-www should end on one preferred URL&lt;/span&gt;
curl &lt;span class="nt"&gt;-sIL&lt;/span&gt; http://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"^(HTTP|location)"&lt;/span&gt;
curl &lt;span class="nt"&gt;-sIL&lt;/span&gt; https://www.example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"^(HTTP|location)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTPS everywhere, no mixed content&lt;/li&gt;
&lt;li&gt;One preferred host, with short redirect chains&lt;/li&gt;
&lt;li&gt;Cookie flags (&lt;code&gt;Secure&lt;/code&gt;, &lt;code&gt;HttpOnly&lt;/code&gt;, &lt;code&gt;SameSite&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;CORS rules that match your actual clients&lt;/li&gt;
&lt;li&gt;Security headers: &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;Strict-Transport-Security&lt;/code&gt;, &lt;code&gt;X-Content-Type-Options&lt;/code&gt;, &lt;code&gt;Referrer-Policy&lt;/code&gt;, and framing controls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not paste a strict CSP from another site and deploy it. It can block your own scripts, fonts, payments, or auth provider. Start in report-only mode, watch what it flags, then enforce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; img-src 'self' data:; report-to csp-endpoint
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" rel="noopener noreferrer"&gt;MDN CSP guide&lt;/a&gt; covers each directive.&lt;/p&gt;

&lt;p&gt;If you use a CDN or proxy, also confirm the origin server is not directly reachable in a way that bypasses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Check what crawlers actually receive
&lt;/h2&gt;

&lt;p&gt;Staging settings leak into production more often than you would expect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Robots directives and canonical on the live page&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;meta&lt;/span&gt;&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="s2"&gt;^&amp;gt;]+robots|&amp;lt;link&lt;/span&gt;&lt;span class="se"&gt;\[&lt;/span&gt;&lt;span class="s2"&gt;^&amp;gt;]+canonical"&lt;/span&gt;

&lt;span class="c"&gt;# Header-level noindex&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; x-robots-tag

curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/robots.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify for key pages: correct status code, no accidental &lt;code&gt;noindex&lt;/code&gt;, a canonical pointing to the preferred production URL, unique title and description, one &lt;code&gt;h1&lt;/code&gt;, crawlable internal links, and a sitemap with live URLs only.&lt;/p&gt;

&lt;p&gt;For client-rendered apps, inspect the rendered HTML. If essential copy, links, or metadata only appear after heavy JavaScript runs, a crawler may not see them. Google's &lt;a href="https://developers.google.com/search/docs/crawling-indexing" rel="noopener noreferrer"&gt;indexing docs&lt;/a&gt; explain how rendering and canonicals are handled.&lt;/p&gt;

&lt;p&gt;Also check social previews: a correct canonical can still ship with an Open Graph image from a builder preview domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Test performance and accessibility on the real build
&lt;/h2&gt;

&lt;p&gt;Measure the deployed build on a mobile profile and a constrained network, not your laptop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx lighthouse https://example.com &lt;span class="se"&gt;\\&lt;/span&gt;
  &lt;span class="nt"&gt;--only-categories&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;performance,accessibility,seo &lt;span class="se"&gt;\\&lt;/span&gt;
  &lt;span class="nt"&gt;--view&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Common causes of slow generated sites: oversized hero images, unused JavaScript, duplicate UI libraries, many font weights, animation packages for small effects, and blocking third-party widgets. Check loading, responsiveness, and layout stability, then complete the main task by hand. A good aggregate score can hide a form that still feels laggy.&lt;/p&gt;

&lt;p&gt;Automated accessibility checks catch missing labels and contrast issues, but not the whole experience. The &lt;a href="https://www.w3.org/WAI/test-evaluate/tools/selecting/" rel="noopener noreferrer"&gt;W3C WAI&lt;/a&gt; is explicit that tools cannot cover every requirement. Manually check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keyboard-only navigation, focus visibility, and focus order&lt;/li&gt;
&lt;li&gt;Persistent form labels and readable error messages&lt;/li&gt;
&lt;li&gt;Alt text on meaningful images&lt;/li&gt;
&lt;li&gt;Zoom and reflow at small viewports&lt;/li&gt;
&lt;li&gt;Reduced-motion behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Assign owners and make a release decision
&lt;/h2&gt;

&lt;p&gt;A report fixes nothing by itself. Give every release-blocking issue one owner, one deadline, and one piece of evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Critical journeys:&lt;/strong&gt; product or QA, with a completed success and failure run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access control and app behavior:&lt;/strong&gt; developer, with role-based test results against the production build&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting, DNS, TLS, CDN:&lt;/strong&gt; platform owner, with verified live configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexing and metadata:&lt;/strong&gt; SEO or marketing, with live URL inspection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics and forms:&lt;/strong&gt; marketing ops, with confirmed events and delivery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One person can own several rows. What matters is that ownership is explicit.&lt;/p&gt;

&lt;p&gt;Then sort findings by action rather than a scanner's severity label:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Block the release:&lt;/strong&gt; exposed production credentials, broken authorization, public sensitive data, unsafe payment or account behavior, a critical journey that cannot be completed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix before public traffic:&lt;/strong&gt; broken forms, accidental indexing blocks, wrong redirects, severe mobile problems, no monitoring on a critical service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule and track:&lt;/strong&gt; lower-impact hardening and cosmetic issues, each with an owner and a date&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investigate:&lt;/strong&gt; unclear, duplicated, or environment-specific findings. Confirm the affected asset before changing production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After every fix, retest on the live environment. A merged PR does not prove your CDN, cache, DNS provider, or pipeline delivered the change.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Plan the first hours after deploy
&lt;/h2&gt;

&lt;p&gt;Before release, decide who watches errors and uptime, who checks form and email delivery, who can roll back, and where launch issues are logged. Know how to restore from backup. Keep the domain registrar, DNS, hosting, repo, and email accounts under team control rather than one person's login. Re-run this review after any change to the domain, hosting, framework, auth, analytics, or integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating part of this
&lt;/h2&gt;

&lt;p&gt;Most of the checks above can be scripted or run with free tools: &lt;code&gt;curl&lt;/code&gt;, Lighthouse, &lt;code&gt;npm audit&lt;/code&gt;, &lt;a href="https://www.zaproxy.org/" rel="noopener noreferrer"&gt;OWASP ZAP&lt;/a&gt;, and &lt;a href="https://www.deque.com/axe/" rel="noopener noreferrer"&gt;axe&lt;/a&gt;. Several hosted scanners also cover the public-surface checks (security headers, performance, SEO, infrastructure) in one pass.&lt;/p&gt;

&lt;p&gt;Disclosure: I work on one of them, &lt;a href="https://flawpilot.com/?utm_source=devto&amp;amp;utm_medium=organic&amp;amp;utm_campaign=ai-built-website-launch-review" rel="noopener noreferrer"&gt;FlawPilot&lt;/a&gt;. Whatever you use, keep the limits in mind. A public scan cannot sign in as each role, inspect private business logic, or judge accessibility in full, and source scanning does not replace runtime testing. Treat automated results as inputs to the release decision, not permission to deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Production-like URL tested, primary journey works end to end&lt;/li&gt;
&lt;li&gt;[ ] Failure and cancellation paths fail safely&lt;/li&gt;
&lt;li&gt;[ ] Authentication and authorization tested separately, with multiple roles&lt;/li&gt;
&lt;li&gt;[ ] No secrets in the bundle, source maps, logs, or Git history&lt;/li&gt;
&lt;li&gt;[ ] Dependencies and third-party scripts reviewed&lt;/li&gt;
&lt;li&gt;[ ] HTTPS, redirects, cookies, CORS, and headers checked on the live response&lt;/li&gt;
&lt;li&gt;[ ] Important pages indexable, with correct canonicals and metadata&lt;/li&gt;
&lt;li&gt;[ ] Performance tested on the production build under mobile conditions&lt;/li&gt;
&lt;li&gt;[ ] Accessibility tested automatically and manually&lt;/li&gt;
&lt;li&gt;[ ] Every open issue has an owner and a release decision&lt;/li&gt;
&lt;li&gt;[ ] Monitoring and rollback responsibilities are clear&lt;/li&gt;
&lt;li&gt;[ ] Critical fixes verified after deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI changes how fast you can build. It does not change what production has to withstand.&lt;/p&gt;

&lt;p&gt;What is the worst thing you have found in an AI-generated codebase before launch? Curious what others check that is missing from this list.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>devops</category>
      <category>ai</category>
    </item>
    <item>
      <title>A Fast AI-Built App Can Still Miss Basic Security Controls</title>
      <dc:creator>FlawPilot</dc:creator>
      <pubDate>Thu, 01 Oct 2026 09:13:06 +0000</pubDate>
      <link>https://dev.to/flawpilot/a-fast-ai-built-app-can-still-miss-basic-security-controls-2ffe</link>
      <guid>https://dev.to/flawpilot/a-fast-ai-built-app-can-still-miss-basic-security-controls-2ffe</guid>
      <description>&lt;p&gt;An application can load quickly, pass a normal click-through test, and still be unready for production.&lt;/p&gt;

&lt;p&gt;That is not a contradiction. Functional testing and security testing answer different questions.&lt;/p&gt;

&lt;p&gt;A functional test asks whether a user can complete the intended journey. A security review asks what else the application, domain, browser, server, and deployment will allow.&lt;/p&gt;

&lt;p&gt;An anonymized review of one AI-built web application made that difference clear. The app scored 100 out of 100 for performance, yet the broader review found 35 open issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 critical&lt;/li&gt;
&lt;li&gt;6 high severity&lt;/li&gt;
&lt;li&gt;19 medium severity&lt;/li&gt;
&lt;li&gt;9 low severity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application was not visibly broken. It loaded fast, rendered correctly, and supported its main workflow. Most of the problems existed outside the path a builder would normally test in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the review measured
&lt;/h2&gt;

&lt;p&gt;The application was assessed across four areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance: 100 out of 100, with no findings&lt;/li&gt;
&lt;li&gt;Security: 70 out of 100, with 16 findings&lt;/li&gt;
&lt;li&gt;Infrastructure: 54 out of 100, with 10 findings&lt;/li&gt;
&lt;li&gt;Search visibility: 46 out of 100, with 9 findings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The combined score was 67 out of 100.&lt;/p&gt;

&lt;p&gt;The perfect performance result was valid. The app handled loading speed, caching, asset delivery, and rendering well. Modern frameworks and AI app builders often provide good defaults for these areas.&lt;/p&gt;

&lt;p&gt;The security and infrastructure findings were also valid. They did not affect the normal user experience, so manual testing had not exposed them.&lt;/p&gt;

&lt;p&gt;This is a common weakness in fast AI-assisted development. The builder checks whether the requested feature works. Nobody checks the surrounding controls unless the release process requires it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing DMARC left the domain easier to impersonate
&lt;/h2&gt;

&lt;p&gt;The domain had no DMARC policy.&lt;/p&gt;

&lt;p&gt;DMARC works with SPF and DKIM to help receiving mail systems evaluate messages that claim to come from a domain. It also lets the domain owner specify what should happen when authentication checks fail.&lt;/p&gt;

&lt;p&gt;Without an appropriate policy, attackers have more room to send email that appears connected to the company. That can support phishing against customers, employees, or partners.&lt;/p&gt;

&lt;p&gt;Nothing about this problem appears in the app interface. A registration form, dashboard, or payment flow can work perfectly while the email domain remains poorly protected.&lt;/p&gt;

&lt;p&gt;Teams should review email authentication whenever a new domain is prepared for production, even if the application itself does not send much email yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser had no Content Security Policy
&lt;/h2&gt;

&lt;p&gt;The application did not send a Content Security Policy header.&lt;/p&gt;

&lt;p&gt;CSP tells the browser which sources may provide scripts, styles, frames, images, and other resources. A well-designed policy can limit what malicious code is allowed to execute if an injection weakness or compromised third-party script reaches a page.&lt;/p&gt;

&lt;p&gt;CSP is not a substitute for fixing cross-site scripting. It is an extra restriction that can reduce impact.&lt;/p&gt;

&lt;p&gt;Adding it carelessly can break legitimate application behavior. Start by listing the resources the app needs, test the policy in a non-production environment, and review browser reports before enforcing it.&lt;/p&gt;

&lt;p&gt;The important point is ownership. If nobody is responsible for response headers, the control may never enter the release checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTPS was present, but HSTS was missing
&lt;/h2&gt;

&lt;p&gt;The application used HTTPS but did not send a Strict-Transport-Security header.&lt;/p&gt;

&lt;p&gt;HSTS tells compatible browsers to use HTTPS for future requests to the domain. It reduces the chance that a visitor's first connection will be downgraded to HTTP on an untrusted network.&lt;/p&gt;

&lt;p&gt;A browser padlock confirms the current page uses HTTPS. It does not confirm that HSTS is configured correctly.&lt;/p&gt;

&lt;p&gt;Before enabling HSTS, confirm that the domain and required subdomains work over HTTPS. A long duration or an &lt;code&gt;includeSubDomains&lt;/code&gt; directive can create an outage if part of the domain still depends on HTTP.&lt;/p&gt;

&lt;p&gt;This is a small configuration change with real consequences, so teams should test it instead of copying a header value without understanding its scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  The app could be framed by another site
&lt;/h2&gt;

&lt;p&gt;The review also found no effective clickjacking protection.&lt;/p&gt;

&lt;p&gt;Without a framing restriction, another website may be able to load the application inside an invisible or misleading frame. An attacker can then try to persuade a user to click a real application control while believing they are interacting with something else.&lt;/p&gt;

&lt;p&gt;The preferred modern control is the &lt;code&gt;frame-ancestors&lt;/code&gt; directive in CSP. Some teams also retain &lt;code&gt;X-Frame-Options&lt;/code&gt; for older browser support.&lt;/p&gt;

&lt;p&gt;Applications that intentionally support embedding need a more precise policy. Blocking every frame is not appropriate when approved partner domains must embed the application.&lt;/p&gt;

&lt;p&gt;Again, the correct setting depends on the product. The AI builder cannot infer that business rule from a generic request to create a dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure findings sat outside the main code path
&lt;/h2&gt;

&lt;p&gt;The review found several other gaps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no CAA record restricting certificate issuance&lt;/li&gt;
&lt;li&gt;no DKIM signature for outgoing email&lt;/li&gt;
&lt;li&gt;server information exposed in responses&lt;/li&gt;
&lt;li&gt;no &lt;code&gt;robots.txt&lt;/code&gt; file for crawler guidance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These findings did not have equal security impact. A missing crawler file should not receive the same response as exposed credentials or broken authorization.&lt;/p&gt;

&lt;p&gt;Their shared cause was a missing review step. The visible product had received attention. Domain, email, server, and deployment configuration had not.&lt;/p&gt;

&lt;p&gt;This distinction matters because teams can waste time if they treat every automated finding as urgent. Severity is a starting point, not the complete decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why vibe coding creates this blind spot
&lt;/h2&gt;

&lt;p&gt;AI coding tools respond to the requirements in the prompt and the context available to them.&lt;/p&gt;

&lt;p&gt;If someone requests a login page, dashboard, database integration, and billing flow, the tool focuses on those capabilities. It may not know the organization's email setup, deployment architecture, data classification, threat model, or access policies.&lt;/p&gt;

&lt;p&gt;Many missing controls do not cause a build failure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a missing security header does not stop the page from rendering&lt;/li&gt;
&lt;li&gt;weak email authentication does not break a dashboard&lt;/li&gt;
&lt;li&gt;excessive cloud permissions do not affect the happy path&lt;/li&gt;
&lt;li&gt;a vulnerable package may continue to work normally&lt;/li&gt;
&lt;li&gt;an exposed secret may remain unused by an attacker for weeks&lt;/li&gt;
&lt;li&gt;a broken database policy may go unnoticed when testing with one account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why "the app works" cannot be used as evidence that the app is secure.&lt;/p&gt;

&lt;p&gt;The issue is not that AI-generated code is automatically unsafe. The issue is that fast generation often removes the independent review that used to happen between implementation and release.&lt;/p&gt;

&lt;p&gt;Teams need to put that review back into the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  A public deployment review cannot inspect everything
&lt;/h2&gt;

&lt;p&gt;A review of a live URL can examine publicly visible behavior and configuration, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TLS configuration&lt;/li&gt;
&lt;li&gt;DNS and email authentication records&lt;/li&gt;
&lt;li&gt;HTTP response headers&lt;/li&gt;
&lt;li&gt;public files and browser assets&lt;/li&gt;
&lt;li&gt;exposed server information&lt;/li&gt;
&lt;li&gt;cross-origin behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It cannot inspect a private repository without authorized access.&lt;/p&gt;

&lt;p&gt;Repository analysis answers different questions. It can look for insecure code patterns, secrets committed to Git history, vulnerable dependency versions, and code that is difficult to review safely.&lt;/p&gt;

&lt;p&gt;Both views matter.&lt;/p&gt;

&lt;p&gt;A source repository can appear clean while the deployed environment has weak headers or incorrect DNS records. A live site can appear well configured while its code contains an injection flaw, an outdated dependency, or a key committed in an older revision.&lt;/p&gt;

&lt;p&gt;Treat repository checks and deployment checks as separate release controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritize findings instead of chasing the total count
&lt;/h2&gt;

&lt;p&gt;The number 35 sounds serious, but the total does not tell a team what to fix first.&lt;/p&gt;

&lt;p&gt;Prioritization should consider at least five factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What an attacker could do&lt;/li&gt;
&lt;li&gt;Whether the affected path is publicly reachable&lt;/li&gt;
&lt;li&gt;Whether sensitive data or privileged actions are involved&lt;/li&gt;
&lt;li&gt;How widely the issue affects the application&lt;/li&gt;
&lt;li&gt;Whether the proposed fix can be tested and rolled back safely&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Leaked production credentials, public database access, broken authorization, and reachable injection flaws normally take priority over low-impact information disclosure or missing search metadata.&lt;/p&gt;

&lt;p&gt;Easy fixes can still be worth doing early when they reduce meaningful risk. The reviewed application could address several high-severity configuration gaps without rewriting application logic. That did not make every fix risk-free. Header and DNS changes still needed testing and verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical pre-release checklist
&lt;/h2&gt;

&lt;p&gt;Before publishing an AI-built web application, verify the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store production secrets outside source control.&lt;/li&gt;
&lt;li&gt;Scan the complete Git history for previously committed credentials.&lt;/li&gt;
&lt;li&gt;Rotate any exposed secret instead of only deleting the file.&lt;/li&gt;
&lt;li&gt;Test authorization with multiple users and roles.&lt;/li&gt;
&lt;li&gt;Confirm database policies prevent cross-account access.&lt;/li&gt;
&lt;li&gt;Review direct and transitive dependencies for known vulnerabilities.&lt;/li&gt;
&lt;li&gt;Restrict CORS to the origins, methods, and headers the application needs.&lt;/li&gt;
&lt;li&gt;Configure relevant security headers and test them in staging.&lt;/li&gt;
&lt;li&gt;Set up SPF, DKIM, and DMARC for domains that send email.&lt;/li&gt;
&lt;li&gt;Remove unnecessary server and framework disclosures.&lt;/li&gt;
&lt;li&gt;Review repository, CI/CD, cloud, and deployment permissions.&lt;/li&gt;
&lt;li&gt;Scan a representative staging deployment before release.&lt;/li&gt;
&lt;li&gt;Check the production URL after deployment.&lt;/li&gt;
&lt;li&gt;Assign an owner and review date to every accepted risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adjust the checklist to the application. A public portfolio has a different risk profile from a multi-tenant product that stores financial, health, or customer information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recheck after deployment
&lt;/h2&gt;

&lt;p&gt;Security review is not complete when a developer merges a fix.&lt;/p&gt;

&lt;p&gt;Confirm that the corrected configuration reached production. A reverse proxy, hosting platform, content delivery network, or environment variable can make the deployed result different from the local version.&lt;/p&gt;

&lt;p&gt;Run checks again after changes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hosting providers&lt;/li&gt;
&lt;li&gt;domains or DNS&lt;/li&gt;
&lt;li&gt;authentication systems&lt;/li&gt;
&lt;li&gt;database policies&lt;/li&gt;
&lt;li&gt;third-party scripts&lt;/li&gt;
&lt;li&gt;dependencies&lt;/li&gt;
&lt;li&gt;deployment workflows&lt;/li&gt;
&lt;li&gt;major application routes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Certificates expire, package vulnerabilities are disclosed, and configuration changes accumulate. A secure launch does not guarantee a secure application six months later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main lesson
&lt;/h2&gt;

&lt;p&gt;The reviewed application was fast. It was functional. It also missed controls that mattered.&lt;/p&gt;

&lt;p&gt;Those facts can all be true at the same time.&lt;/p&gt;

&lt;p&gt;AI-assisted development reduces the time required to turn an idea into a working application. It does not remove the need to review code, dependencies, permissions, domain settings, deployment configuration, and the final production result.&lt;/p&gt;

&lt;p&gt;Keep the speed advantage. Add a security checkpoint before launch, then verify the application again after it reaches production.&lt;/p&gt;

</description>
      <category>security</category>
      <category>seo</category>
      <category>web</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>How to choose a SAST tool: 8 open-source options and a broader security platform</title>
      <dc:creator>FlawPilot</dc:creator>
      <pubDate>Thu, 24 Sep 2026 12:02:03 +0000</pubDate>
      <link>https://dev.to/flawpilot/how-to-choose-a-sast-tool-8-open-source-options-and-a-broader-security-platform-2og8</link>
      <guid>https://dev.to/flawpilot/how-to-choose-a-sast-tool-8-open-source-options-and-a-broader-security-platform-2og8</guid>
      <description>&lt;p&gt;Static application security testing helps developers find risky code without running the application. That definition is simple. Choosing a scanner is not.&lt;/p&gt;

&lt;p&gt;A tool may support your programming language but miss the framework patterns that matter in your project. Another may produce useful findings but require more maintenance than your team can manage. A third may work well in continuous integration but provide little help when developers need to understand or fix an alert.&lt;/p&gt;

&lt;p&gt;This guide compares eight open-source SAST tools and FlawPilot, a broader code and application security platform. The goal is to help you build a shortlist based on your codebase, workflow, and security needs.&lt;/p&gt;

&lt;p&gt;Disclosure: The author is affiliated with FlawPilot. It is included in third position and assessed using the same practical criteria as the other options.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SAST checks
&lt;/h2&gt;

&lt;p&gt;SAST examines source code, bytecode, or build artifacts without sending test traffic to a running application. Depending on the engine and language, it may detect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unsafe input handling&lt;/li&gt;
&lt;li&gt;Injection paths&lt;/li&gt;
&lt;li&gt;Hardcoded credentials&lt;/li&gt;
&lt;li&gt;Weak cryptographic choices&lt;/li&gt;
&lt;li&gt;Unsafe deserialization&lt;/li&gt;
&lt;li&gt;Path traversal risks&lt;/li&gt;
&lt;li&gt;Cross-site scripting paths&lt;/li&gt;
&lt;li&gt;Risky functions or insecure code patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many SAST tools can run on a developer's machine, during a pull request, or in a continuous integration pipeline. They often identify the file and line connected to a finding, which gives the developer a place to begin the investigation.&lt;/p&gt;

&lt;p&gt;That finding is not proof of exploitation. The scanner may not understand every validation step, authorization control, runtime condition, or business rule. A developer still needs to check whether the code is reachable, whether an attacker can control the input, and what the impact would be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why source scanning and live testing are different
&lt;/h2&gt;

&lt;p&gt;SAST reads code. Dynamic or live application testing interacts with a running system.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Source scanning&lt;/th&gt;
&lt;th&gt;Live application scanning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What does it inspect?&lt;/td&gt;
&lt;td&gt;Source code, bytecode, or build artifacts&lt;/td&gt;
&lt;td&gt;A running website, API, or web application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;When can it run?&lt;/td&gt;
&lt;td&gt;During development and continuous integration&lt;/td&gt;
&lt;td&gt;In a test environment, before launch, or after deployment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What context does it see?&lt;/td&gt;
&lt;td&gt;Internal code paths and data flow&lt;/td&gt;
&lt;td&gt;Public behavior, responses, services, and configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What can it miss?&lt;/td&gt;
&lt;td&gt;Runtime settings and external exposure&lt;/td&gt;
&lt;td&gt;Internal code that is not reachable during the test&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One method cannot replace the other. A source scanner may identify an unsafe query construction. A live scanner may identify missing security headers, weak transport settings, or an exposed service. Teams that build internet-facing applications usually need both views.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Main focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Semgrep Community Edition&lt;/td&gt;
&lt;td&gt;Multi-language repositories and custom rules&lt;/td&gt;
&lt;td&gt;Pattern-based source analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeQL&lt;/td&gt;
&lt;td&gt;Projects hosted in GitHub workflows&lt;/td&gt;
&lt;td&gt;Semantic analysis and code queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlawPilot&lt;/td&gt;
&lt;td&gt;Teams that want source and deployed-application checks&lt;/td&gt;
&lt;td&gt;Code scanning, live checks, and AI Fix prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandit&lt;/td&gt;
&lt;td&gt;Python projects&lt;/td&gt;
&lt;td&gt;Python security rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brakeman&lt;/td&gt;
&lt;td&gt;Ruby on Rails applications&lt;/td&gt;
&lt;td&gt;Rails-aware static analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gosec&lt;/td&gt;
&lt;td&gt;Go services and applications&lt;/td&gt;
&lt;td&gt;Go-specific security checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SpotBugs with Find Security Bugs&lt;/td&gt;
&lt;td&gt;Java and JVM projects&lt;/td&gt;
&lt;td&gt;Bytecode analysis with security detectors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MobSF&lt;/td&gt;
&lt;td&gt;Mobile application assessment&lt;/td&gt;
&lt;td&gt;Mobile static and dynamic analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PMD&lt;/td&gt;
&lt;td&gt;Java-heavy projects with code-quality needs&lt;/td&gt;
&lt;td&gt;General static rules with selected security checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Capabilities, licenses, and supported languages can change. Confirm current details before adopting a tool across multiple repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Semgrep Community Edition
&lt;/h2&gt;

&lt;p&gt;Semgrep Community Edition scans source code with rules that describe insecure or unwanted patterns. It supports many languages, though the depth of support is not identical across all of them.&lt;/p&gt;

&lt;p&gt;Its main advantage is flexibility. A team can use community rules, adjust existing rules, or write checks for patterns specific to its own code. Developers can run it locally and add it to a pull-request or continuous integration workflow.&lt;/p&gt;

&lt;p&gt;That flexibility requires ownership. Someone needs to choose the rules, test them against the codebase, remove irrelevant checks, and maintain custom rules as frameworks change. Enabling a large rule collection without tuning can create noise.&lt;/p&gt;

&lt;p&gt;Semgrep is worth considering when you have several languages, want editable rules, and have someone who can maintain the rule set.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. CodeQL
&lt;/h2&gt;

&lt;p&gt;CodeQL creates a database representation of a codebase and lets security queries analyze relationships and data flow. This approach can identify problems that simple pattern matching may not find.&lt;/p&gt;

&lt;p&gt;It fits naturally into GitHub-based development. Findings can appear in code-scanning workflows and pull requests for supported languages. Security engineers can also write custom queries for organization-specific risks.&lt;/p&gt;

&lt;p&gt;The tradeoff is complexity. Advanced query development requires knowledge of the CodeQL language and its libraries. Some compiled projects also need correct build configuration before analysis can work well.&lt;/p&gt;

&lt;p&gt;CodeQL is a strong candidate when repositories already use GitHub and the team needs deeper semantic analysis. Check the current licensing and availability conditions for your repository type and plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. FlawPilot
&lt;/h2&gt;

&lt;p&gt;FlawPilot covers source code and the deployed application. Teams can connect a repository for code scanning and scan a website, web application, or SaaS product before or after launch.&lt;/p&gt;

&lt;p&gt;The code scan looks for insecure code, exposed secrets, and vulnerable dependencies. The live scan checks publicly visible security, performance, infrastructure, and SEO signals. This combination helps a developer compare what exists in the repository with what the deployed environment exposes.&lt;/p&gt;

&lt;p&gt;For supported findings, FlawPilot supplies an AI Fix prompt. A developer can copy that prompt into a coding assistant to receive finding-specific remediation guidance. The developer should review the resulting change, run the relevant tests, and scan again before deployment.&lt;/p&gt;

&lt;p&gt;FlawPilot may suit founders and development teams that want prioritized explanations, repository checks, and live scanning in one workflow. It does not replace a manual penetration test. Automated checks can miss business-logic problems, complex authorization failures, authenticated paths, and attacks that depend on several weaknesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Bandit
&lt;/h2&gt;

&lt;p&gt;Bandit scans Python abstract syntax trees and applies security-focused plugins. Its checks cover patterns such as hardcoded passwords, unsafe subprocess use, weak cryptography, and dangerous function calls.&lt;/p&gt;

&lt;p&gt;The narrow focus is useful for Python teams. Bandit is easy to run locally or inside continuous integration, and it can produce structured output for other development tools.&lt;/p&gt;

&lt;p&gt;Bandit still needs tuning. A rule may report code that is safe in the actual application context. Teams should document suppressions and review them instead of allowing an ignore list to grow without ownership.&lt;/p&gt;

&lt;p&gt;Bandit does not check whether installed Python packages contain known vulnerabilities. Pair it with dependency analysis when assessing a Python project.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Brakeman
&lt;/h2&gt;

&lt;p&gt;Brakeman is designed for Ruby on Rails. It understands Rails conventions and reviews application code without starting the application server.&lt;/p&gt;

&lt;p&gt;Its framework knowledge helps it identify Rails-related injection, redirect, cross-site scripting, and configuration risks. It can run from the command line and in automated build workflows.&lt;/p&gt;

&lt;p&gt;Brakeman is a focused choice, not a complete scanner for a mixed technology stack. A system with a Rails backend, a separate frontend, infrastructure files, and cloud services will require other checks.&lt;/p&gt;

&lt;p&gt;Teams should tune warning confidence and review ignored findings after important code changes. A warning that seemed irrelevant in one release may matter after the surrounding logic changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Gosec
&lt;/h2&gt;

&lt;p&gt;Gosec examines Go source code using security rules built around Go analysis packages. It can identify risky permissions, hardcoded credentials, weak cryptography, unsafe integer conversions, and other Go-specific patterns.&lt;/p&gt;

&lt;p&gt;It fits into Go development workflows and can export results in formats used by code-scanning systems. That makes it practical for services that already run tests, formatting, and analysis in continuous integration.&lt;/p&gt;

&lt;p&gt;Gosec is different from a general Go linter. A linter usually emphasizes correctness, consistency, and maintainability. Gosec adds security rules, but teams still need separate dependency analysis and testing of the running service.&lt;/p&gt;

&lt;p&gt;Review each rule against the application. A command-line utility and a public API have different exposure and may need different rule settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. SpotBugs with Find Security Bugs
&lt;/h2&gt;

&lt;p&gt;SpotBugs analyzes Java bytecode for patterns associated with programming defects. The Find Security Bugs plugin adds security detectors for Java web and Android applications and can also support relevant patterns in other JVM languages.&lt;/p&gt;

&lt;p&gt;This combination fits Maven and Gradle workflows. It is useful for teams that want general defect checks and security rules during the same build process.&lt;/p&gt;

&lt;p&gt;Scan quality depends on build quality. Missing classes or an incomplete type hierarchy can reduce the analyzer's understanding of the application. Treat those build warnings as scan problems rather than harmless messages.&lt;/p&gt;

&lt;p&gt;SpotBugs alone is not a complete application-security scanner. Make sure the security plugin is installed and configured if security analysis is the objective.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. MobSF
&lt;/h2&gt;

&lt;p&gt;Mobile Security Framework, commonly called MobSF, is designed for Android, iOS, and Windows mobile application assessment. It can perform static and dynamic analysis, depending on the application artifact and test setup.&lt;/p&gt;

&lt;p&gt;MobSF can inspect permissions, certificates, application components, embedded files, and mobile platform configuration. That makes it different from scanners aimed at ordinary web application source code.&lt;/p&gt;

&lt;p&gt;The broad mobile coverage requires more setup than a small language-specific scanner. Dynamic analysis needs a suitable environment, and the results need review by someone who understands the mobile platform and the application.&lt;/p&gt;

&lt;p&gt;Mobile security also includes backend APIs, authentication, data handling, dependencies, and high-risk user flows. MobSF should form one part of that process.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. PMD
&lt;/h2&gt;

&lt;p&gt;PMD checks source code for programming problems, duplicated code, maintainability issues, and selected security patterns. It is strongly associated with Java, although it has modules for other languages.&lt;/p&gt;

&lt;p&gt;It works well when a team wants one rule system for code quality and some security checks. Java projects can add it to common build workflows and create project-specific rules.&lt;/p&gt;

&lt;p&gt;PMD is not as security-focused as Bandit, Brakeman, or Gosec. Treat its security rules as an extra layer. A Java application that needs deeper security analysis may pair PMD with a dedicated security tool.&lt;/p&gt;

&lt;p&gt;Avoid enabling every rule at once. Select checks that apply to the codebase, then expand the rule set as the team learns how to handle the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to build a useful shortlist
&lt;/h2&gt;

&lt;p&gt;Tool selection should begin with your repository. Popularity and long feature lists are poor substitutes for testing a scanner against real project code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Match the language and framework
&lt;/h3&gt;

&lt;p&gt;Confirm that the scanner supports the language version and framework you use. Basic syntax support does not always mean deep framework-aware analysis.&lt;/p&gt;

&lt;p&gt;For a mixed stack, decide whether one multi-language scanner provides enough coverage or whether each major language needs a focused tool. A focused scanner often gives better framework context, while a multi-language tool can reduce operational work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decide where feedback should appear
&lt;/h3&gt;

&lt;p&gt;Choose when developers need results. Options include the editor, a local command, a pull request, a continuous integration job, or a scheduled scan.&lt;/p&gt;

&lt;p&gt;Begin with reporting. Blocking every build on the first day can disrupt delivery if the scanner reports old issues or irrelevant patterns. After tuning the rules and reviewing the existing findings, block only new results that meet a clear severity and confidence threshold.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test a representative repository
&lt;/h3&gt;

&lt;p&gt;Run each shortlisted tool against code that reflects your normal architecture. Then review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether the findings are relevant&lt;/li&gt;
&lt;li&gt;Whether each result points to a useful code location&lt;/li&gt;
&lt;li&gt;How often the team sees false positives&lt;/li&gt;
&lt;li&gt;Whether the explanation helps a developer investigate&lt;/li&gt;
&lt;li&gt;Whether the output works with existing systems&lt;/li&gt;
&lt;li&gt;How much time the scan adds to the pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not compare tools using the total number of alerts. A scanner that reports more issues is not automatically better. Review the accuracy and usefulness of those findings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check rule controls and suppressions
&lt;/h3&gt;

&lt;p&gt;The team needs a way to disable irrelevant rules, exclude generated files, record accepted risks, and create project-specific checks when necessary.&lt;/p&gt;

&lt;p&gt;Every suppression should have a reason and an owner. Review accepted risks after major architecture changes or framework upgrades. Otherwise, an old exception can hide a new problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Review maintenance and licensing
&lt;/h3&gt;

&lt;p&gt;Check release activity, supported language versions, open issues, documentation, and the health of the contributor community. Also review the license for the scanner, plugins, and rule packs.&lt;/p&gt;

&lt;p&gt;Open source does not mean there is no operating cost. Installation, upgrades, continuous integration jobs, rule maintenance, result triage, and developer support all require time.&lt;/p&gt;

&lt;h2&gt;
  
  
  A staged rollout for development teams
&lt;/h2&gt;

&lt;p&gt;A gradual rollout gives the team time to understand the scanner before it controls releases.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select one active repository with supported languages.&lt;/li&gt;
&lt;li&gt;Run the scanner in reporting mode.&lt;/li&gt;
&lt;li&gt;Review the first results with a developer who knows the code.&lt;/li&gt;
&lt;li&gt;Disable irrelevant rules and document justified suppressions.&lt;/li&gt;
&lt;li&gt;Fix high-confidence findings with meaningful impact.&lt;/li&gt;
&lt;li&gt;Record a baseline for accepted existing findings.&lt;/li&gt;
&lt;li&gt;Block new critical findings once the output is reliable.&lt;/li&gt;
&lt;li&gt;Review tool versions, rules, and suppressions on a schedule.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process separates existing security debt from newly introduced problems. The team can stop new high-risk issues while handling older findings through planned work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SAST does not cover
&lt;/h2&gt;

&lt;p&gt;Static analysis cannot see every security problem. A complete testing process may also require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependency analysis&lt;/li&gt;
&lt;li&gt;Secret scanning&lt;/li&gt;
&lt;li&gt;Infrastructure-as-code checks&lt;/li&gt;
&lt;li&gt;Container image scanning&lt;/li&gt;
&lt;li&gt;API security testing&lt;/li&gt;
&lt;li&gt;Live application scanning&lt;/li&gt;
&lt;li&gt;Manual testing of authorization and business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose the testing mix based on the application. A public content website, an authenticated SaaS product, and a financial mobile application do not have the same exposure or impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Which open-source SAST tool should I choose?
&lt;/h3&gt;

&lt;p&gt;Choose according to the codebase. Semgrep supports many languages and custom rules. Bandit focuses on Python, Brakeman on Ruby on Rails, Gosec on Go, and MobSF on mobile applications. Test shortlisted tools on your own repository before deciding.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can SAST find every vulnerability?
&lt;/h3&gt;

&lt;p&gt;No. SAST can find insecure patterns and some risky data flows, but it may miss runtime configuration, vulnerable dependencies, authorization failures, exposed services, and business-logic flaws.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should a team run SAST?
&lt;/h3&gt;

&lt;p&gt;Run it while developers write and review code, then repeat the scan in continuous integration. Start in reporting mode and introduce release blocking after the team has tuned the rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is dependency scanning the same as SAST?
&lt;/h3&gt;

&lt;p&gt;No. SAST analyzes code written for the application. Dependency scanning checks third-party packages and versions against known vulnerability information. Most projects need both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is SAST enough before launch?
&lt;/h3&gt;

&lt;p&gt;No. Test secrets, dependencies, authentication, authorization, APIs, infrastructure configuration, and the deployed environment. High-risk systems may also need manual penetration testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can SAST scan AI-generated code?
&lt;/h3&gt;

&lt;p&gt;Yes, if the scanner supports the generated languages and frameworks. Review AI-generated code using the same security controls as human-written code. Developers must still confirm findings and test the deployed application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final guidance
&lt;/h2&gt;

&lt;p&gt;The right SAST tool is the one your team can run, understand, tune, and maintain. Start with language support and workflow fit. Test the output against a real repository before creating release rules.&lt;/p&gt;

&lt;p&gt;Static analysis gives developers visibility into code risks. Dependency checks, secret scanning, live testing, and manual review cover problems that source analysis cannot see. Use the combination that matches the application's exposure and risk.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>security</category>
      <category>infrastructure</category>
      <category>ai</category>
    </item>
    <item>
      <title>A Developer-Friendly Workflow for Triaging Website Security Alerts</title>
      <dc:creator>FlawPilot</dc:creator>
      <pubDate>Fri, 18 Sep 2026 07:40:14 +0000</pubDate>
      <link>https://dev.to/flawpilot/a-developer-friendly-workflow-for-triaging-website-security-alerts-3o90</link>
      <guid>https://dev.to/flawpilot/a-developer-friendly-workflow-for-triaging-website-security-alerts-3o90</guid>
      <description>&lt;p&gt;A security scanner reports a missing header, an exposed key, an unsafe cookie, and a certificate warning. Which one should the team fix first?&lt;/p&gt;

&lt;p&gt;The severity label helps, but it cannot answer that question by itself. A scanner does not know whether the affected asset is public, whether the credential is still valid, how many users depend on the service, or whether anyone is exploiting the weakness.&lt;/p&gt;

&lt;p&gt;Developers need a repeatable way to turn scanner output into engineering work. The workflow below covers the full path: capture the evidence, validate it, decide whether the problem is an incident, assign an owner, make a safe change, and verify production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalize the alert before discussing priority
&lt;/h2&gt;

&lt;p&gt;Security tools describe findings in different ways. Before comparing them, put each alert into the same record format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;finding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Public&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;found&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;client-side&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;JavaScript"&lt;/span&gt;
  &lt;span class="na"&gt;asset&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com/assets/app.js"&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt;
  &lt;span class="na"&gt;detected_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YYYY-MM-DD&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;HH:MM&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;UTC"&lt;/span&gt;
  &lt;span class="na"&gt;scanner_severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high"&lt;/span&gt;
  &lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Key&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pattern&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;scan"&lt;/span&gt;

&lt;span class="na"&gt;triage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publicly_reachable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;authentication_required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;sensitive_system_affected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown"&lt;/span&gt;
  &lt;span class="na"&gt;active_misuse_observed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown"&lt;/span&gt;
  &lt;span class="na"&gt;temporary_control_available&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unassigned"&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new"&lt;/span&gt;
  &lt;span class="na"&gt;containment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;started"&lt;/span&gt;
  &lt;span class="na"&gt;permanent_fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;started"&lt;/span&gt;
  &lt;span class="na"&gt;production_retest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not place the full value of a secret, session token, or sensitive record in a general-purpose ticket. Record enough evidence to identify the issue, then store sensitive evidence in a restricted system.&lt;/p&gt;

&lt;p&gt;This common format prevents several mistakes. It separates the scanner's assessment from the team's assessment. It also makes missing information visible instead of letting people assume that someone else checked it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate the finding against the correct asset
&lt;/h2&gt;

&lt;p&gt;Validation answers two questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the reported condition still exist?&lt;/li&gt;
&lt;li&gt;Does the evidence point to the actual cause?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start with the exact URL, hostname, file, port, certificate, DNS record, cookie, or response header named in the report. Confirm that it belongs to the intended environment.&lt;/p&gt;

&lt;p&gt;Production and staging may behave differently because of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CDN or reverse-proxy configuration&lt;/li&gt;
&lt;li&gt;Environment-specific headers&lt;/li&gt;
&lt;li&gt;Redirects between hostnames&lt;/li&gt;
&lt;li&gt;Browser or edge caching&lt;/li&gt;
&lt;li&gt;Different certificates&lt;/li&gt;
&lt;li&gt;Feature flags&lt;/li&gt;
&lt;li&gt;Old deployment assets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an HTTP header finding, inspect the response returned by the public production URL. For a DNS finding, query the authoritative record rather than relying on an old screenshot. For a client-side exposure, inspect the deployed asset instead of checking only the current source branch.&lt;/p&gt;

&lt;p&gt;Do not dismiss a finding because the page loads correctly. Missing cookie flags, loose cross-origin rules, and weak response headers often have no visible effect on the interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate a security finding from a security incident
&lt;/h2&gt;

&lt;p&gt;A finding reports an unsafe or uncertain condition. An incident involves suspected or confirmed misuse, unauthorized access, data exposure, or service disruption.&lt;/p&gt;

&lt;p&gt;A missing &lt;code&gt;Content-Security-Policy&lt;/code&gt; header is normally a remediation task. A public credential with unexpected activity may require incident response.&lt;/p&gt;

&lt;p&gt;Look for evidence such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication events nobody recognizes&lt;/li&gt;
&lt;li&gt;Requests made with an exposed credential&lt;/li&gt;
&lt;li&gt;Unexpected administrative changes&lt;/li&gt;
&lt;li&gt;Access to data outside an expected pattern&lt;/li&gt;
&lt;li&gt;Unexplained traffic spikes or service disruption&lt;/li&gt;
&lt;li&gt;Cloud, hosting, or repository alerts connected to the finding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you see these signs, preserve relevant logs before making changes that could destroy evidence. Escalate according to the organization's incident process. An external website scan cannot determine what happened inside private accounts, logs, or authenticated workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritize with context, not severity alone
&lt;/h2&gt;

&lt;p&gt;Use the scanner severity as one input. Then review four contextual factors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reachability
&lt;/h3&gt;

&lt;p&gt;Can an unauthenticated person reach the affected asset from the public internet? A production endpoint that anyone can access usually deserves more attention than a private development service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impact
&lt;/h3&gt;

&lt;p&gt;What could a successful misuse affect? Give more weight to findings connected to user sessions, privileged accounts, production credentials, payment paths, personal data, or administrative functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preconditions
&lt;/h3&gt;

&lt;p&gt;What must happen before the weakness can be used? A flaw that requires an authenticated administrator and an unusual configuration has different urgency from a working secret inside a public JavaScript bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Current evidence
&lt;/h3&gt;

&lt;p&gt;Is the risk theoretical, reproducible, or already being misused? Evidence of active misuse moves the work out of normal backlog prioritization.&lt;/p&gt;

&lt;p&gt;After this review, place the finding into one of four action groups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contain now:&lt;/strong&gt; suspected misuse, exposed credentials, unauthorized access, or active disruption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix next:&lt;/strong&gt; public weakness with meaningful impact and a practical path to misuse&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schedule:&lt;/strong&gt; missing defense or weak configuration with limited current exposure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Investigate:&lt;/strong&gt; stale, duplicated, environment-specific, or unclear evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This classification is an engineering aid. It does not replace contractual, regulatory, or legal response requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assign the person who controls the affected system
&lt;/h2&gt;

&lt;p&gt;An alert sent to an entire channel often has no owner. Assign one person to coordinate the next action and confirm that they accepted it.&lt;/p&gt;

&lt;p&gt;Ownership usually follows the control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application developers own authentication logic, cookie settings, and application-level cross-origin behavior.&lt;/li&gt;
&lt;li&gt;Platform or hosting owners handle response headers, redirects, certificates, public services, and edge configuration.&lt;/li&gt;
&lt;li&gt;Domain or email administrators handle DNSSEC, CAA, SPF, DKIM, and DMARC.&lt;/li&gt;
&lt;li&gt;The developer and service-account owner should work together when a credential is exposed.&lt;/li&gt;
&lt;li&gt;A security or incident-response specialist should guide work when misuse or data exposure is possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The coordinator does not need to make every change. Their job is to keep the alert from becoming an unowned message thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contain immediate risk before completing the repair
&lt;/h2&gt;

&lt;p&gt;Containment reduces exposure while the team works on the root cause.&lt;/p&gt;

&lt;p&gt;If a credential is public, revoke or rotate it. Deleting the value from the latest source file is not sufficient. Copies may remain in build artifacts, browser downloads, CDN caches, deployment history, logs, or Git history.&lt;/p&gt;

&lt;p&gt;After rotation, restrict the replacement credential where possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limit its permissions&lt;/li&gt;
&lt;li&gt;Restrict allowed domains or IP addresses&lt;/li&gt;
&lt;li&gt;Set usage limits&lt;/li&gt;
&lt;li&gt;Separate production and development credentials&lt;/li&gt;
&lt;li&gt;Enable provider-side monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a route or service appears to be under active attack, a temporary response may include disabling the route, restricting access, adding a narrow web application firewall rule, or rolling back a release.&lt;/p&gt;

&lt;p&gt;Containment is not closure. Keep the task open until the team fixes the cause and verifies the live system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the smallest safe change
&lt;/h2&gt;

&lt;p&gt;Broad configuration changes can break authentication, payments, analytics, embedded tools, or third-party scripts.&lt;/p&gt;

&lt;p&gt;Content Security Policy is a common example. Copying a strict policy from an unrelated site may block resources your application needs. Build the policy around the actual scripts, frames, styles, fonts, and connections used by your application. Test the affected user journeys before enforcing it in production.&lt;/p&gt;

&lt;p&gt;Apply the same discipline to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cross-origin resource sharing rules&lt;/li&gt;
&lt;li&gt;Cookie attributes&lt;/li&gt;
&lt;li&gt;Redirect behavior&lt;/li&gt;
&lt;li&gt;Cache controls&lt;/li&gt;
&lt;li&gt;TLS and certificate changes&lt;/li&gt;
&lt;li&gt;DNS records&lt;/li&gt;
&lt;li&gt;Storage permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use staging when it represents production accurately. Prepare a rollback path for changes that affect traffic, authentication, or external integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retest the public result after deployment
&lt;/h2&gt;

&lt;p&gt;A merged pull request does not prove that the finding disappeared from production.&lt;/p&gt;

&lt;p&gt;The application may still serve an old asset or cached response. The change may exist only in staging. A configuration file may not be connected to the active service.&lt;/p&gt;

&lt;p&gt;Use this verification sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the change through the normal release process.&lt;/li&gt;
&lt;li&gt;Repeat the original check against the same production asset.&lt;/li&gt;
&lt;li&gt;Confirm that the original evidence is gone.&lt;/li&gt;
&lt;li&gt;Test the user journey that depends on the changed control.&lt;/li&gt;
&lt;li&gt;Check for new warnings or broken behavior.&lt;/li&gt;
&lt;li&gt;Attach the new evidence to the ticket.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Close the task only when the production result matches the intended state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a reusable remediation issue template
&lt;/h2&gt;

&lt;p&gt;The following Markdown template works in most issue trackers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Finding&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Title:
&lt;span class="p"&gt;-&lt;/span&gt; Affected asset:
&lt;span class="p"&gt;-&lt;/span&gt; Environment:
&lt;span class="p"&gt;-&lt;/span&gt; Detected at:
&lt;span class="p"&gt;-&lt;/span&gt; Scanner severity:
&lt;span class="p"&gt;-&lt;/span&gt; Evidence location:

&lt;span class="gu"&gt;## Validation&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] Correct asset and environment confirmed
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Finding reproduced or independently verified
&lt;span class="p"&gt;-&lt;/span&gt; [ ] False-positive conditions reviewed
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Sensitive evidence stored securely

&lt;span class="gu"&gt;## Triage&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Publicly reachable: Yes / No / Unknown
&lt;span class="p"&gt;-&lt;/span&gt; Authentication required: Yes / No / Unknown
&lt;span class="p"&gt;-&lt;/span&gt; Potential impact:
&lt;span class="p"&gt;-&lt;/span&gt; Preconditions:
&lt;span class="p"&gt;-&lt;/span&gt; Signs of active misuse: Yes / No / Unknown
&lt;span class="p"&gt;-&lt;/span&gt; Action group: Contain now / Fix next / Schedule / Investigate

&lt;span class="gu"&gt;## Ownership&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Coordinator:
&lt;span class="p"&gt;-&lt;/span&gt; Technical owner:
&lt;span class="p"&gt;-&lt;/span&gt; Target date:
&lt;span class="p"&gt;-&lt;/span&gt; Escalation contact:

&lt;span class="gu"&gt;## Response&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Containment action:
&lt;span class="p"&gt;-&lt;/span&gt; Root cause:
&lt;span class="p"&gt;-&lt;/span&gt; Permanent fix:
&lt;span class="p"&gt;-&lt;/span&gt; Rollback plan:

&lt;span class="gu"&gt;## Verification&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Production deployment:
&lt;span class="p"&gt;-&lt;/span&gt; Original check repeated:
&lt;span class="p"&gt;-&lt;/span&gt; User journey tested:
&lt;span class="p"&gt;-&lt;/span&gt; New issues found:
&lt;span class="p"&gt;-&lt;/span&gt; Evidence attached:
&lt;span class="p"&gt;-&lt;/span&gt; Final status:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adjust the fields to match the team's incident process and access controls. Avoid copying secrets or personal data into the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the workflow before the next alert
&lt;/h2&gt;

&lt;p&gt;Write down who reviews new findings, where the team records them, and which conditions start an incident response. Document who can rotate credentials, change DNS, update hosting configuration, and deploy emergency fixes.&lt;/p&gt;

&lt;p&gt;The policy should also define how the team accepts a known risk and when the same asset will be checked again. A finding should not disappear simply because the current sprint ended.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://csrc.nist.gov/pubs/sp/800/61/r3/final" rel="noopener noreferrer"&gt;NIST SP 800-61 Revision 3&lt;/a&gt; connects preparation, detection, response, and recovery. A small team may combine several roles, but it still needs clear ownership and an escalation path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;Scanner output is evidence, not a completed decision. Validate the affected asset, add technical and business context, and assign a person who can move the work forward.&lt;/p&gt;

&lt;p&gt;For urgent exposure, contain first. For normal remediation, make a controlled change and retest the public system. The alert is resolved only when production evidence confirms the fix.&lt;/p&gt;




&lt;p&gt;This article is adapted from an &lt;a href="https://flawpilot.com/blog/how-to-respond-to-website-security-alerts" rel="noopener noreferrer"&gt;original guide published on FlawPilot&lt;/a&gt;. It contains no affiliate links or paid placement.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>cybersecurity</category>
      <category>beginners</category>
    </item>
    <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>
