<?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>Forem: Keuntae Park</title>
    <description>The latest articles on Forem by Keuntae Park (@keuntaepark).</description>
    <link>https://forem.com/keuntaepark</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3835280%2F6035ebb2-fbff-434a-8fb5-f675458c8db0.png</url>
      <title>Forem: Keuntae Park</title>
      <link>https://forem.com/keuntaepark</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/keuntaepark"/>
    <language>en</language>
    <item>
      <title>My cursor-generated app had security issues. It scored 0 out of 100.</title>
      <dc:creator>Keuntae Park</dc:creator>
      <pubDate>Sun, 22 Mar 2026 07:15:42 +0000</pubDate>
      <link>https://forem.com/keuntaepark/my-cursor-generated-app-had-security-issues-it-scored-0-out-of-100-3pn4</link>
      <guid>https://forem.com/keuntaepark/my-cursor-generated-app-had-security-issues-it-scored-0-out-of-100-3pn4</guid>
      <description>&lt;p&gt;Built a Flask app with Cursor last week. Login, dashboard, API — took about 20 minutes. Everything worked great. Then I got curious and ran a security scanner on it. 0 out of 100. Grade F. lol&lt;/p&gt;

&lt;p&gt;The app runs perfectly fine. It just happens to be completely exploitable if anyone bothers to look. So I scanned about 10 more open source vibe-coded projects on GitHub. 8 out of 10 had similar issues. AI picks the shortest path to "it works" and that path is almost always the least secure one.&lt;/p&gt;

&lt;p&gt;This bugged me enough that I built a GitHub Action that scans every PR automatically. One YAML file, posts findings as PR comments with the exact line and how to fix it.&lt;br&gt;
To be clear about what it can't do:&lt;/p&gt;

&lt;p&gt;No business logic bugs — if your auth flow is broken by design, pattern matching won't catch it&lt;br&gt;
Static analysis only — reads code, doesn't run your app&lt;br&gt;
Doesn't catch everything — focuses on patterns AI commonly gets wrong&lt;/p&gt;

&lt;p&gt;I'm not a security expert, which is exactly why I needed something like this. If you're vibe coding and shipping without reviewing what AI wrote, might be worth a quick scan. Results can be... humbling.&lt;br&gt;
Repo: &lt;a href="https://github.com/vibesafeio/vibesafe-action" rel="noopener noreferrer"&gt;https://github.com/vibesafeio/vibesafe-action&lt;/a&gt;&lt;br&gt;
Free, open source, no account needed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I asked Claude to build me an app. It had 36 security holes.</title>
      <dc:creator>Keuntae Park</dc:creator>
      <pubDate>Fri, 20 Mar 2026 11:29:37 +0000</pubDate>
      <link>https://forem.com/keuntaepark/i-built-a-free-security-scanner-for-vibe-coded-apps-heres-what-it-catches-34fd</link>
      <guid>https://forem.com/keuntaepark/i-built-a-free-security-scanner-for-vibe-coded-apps-heres-what-it-catches-34fd</guid>
      <description>&lt;p&gt;Last week I vibe-coded a Flask app with Cursor. Login, dashboard, API — the whole thing. Took about 20 minutes. Everything worked.&lt;/p&gt;

&lt;p&gt;Then I got curious and ran a security scanner on it.&lt;/p&gt;

&lt;p&gt;Score: 0 out of 100. Grade F.&lt;/p&gt;

&lt;p&gt;Here's what the AI wrote for me without me asking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;eval(user_input)&lt;/code&gt; — lets anyone run arbitrary code on my server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subprocess.run(cmd, shell=True)&lt;/code&gt; — command injection&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;f"SELECT * FROM users WHERE id = {user_id}"&lt;/code&gt; — SQL injection&lt;/li&gt;
&lt;li&gt;A JWT secret hardcoded as &lt;code&gt;"secret123"&lt;/code&gt; right in the source&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every single one of these worked perfectly. The app ran fine. But anyone who knew what to look for could've owned my entire server.&lt;/p&gt;

&lt;p&gt;This isn't just me&lt;/p&gt;

&lt;p&gt;I started looking at other vibe-coded projects on GitHub. Apps built with Lovable, Bolt, Cursor. I scanned 10 of them.&lt;/p&gt;

&lt;p&gt;8 out of 10 had issues. Missing alt attributes on images (accessibility lawsuits are a real thing — 4,000+ ADA cases filed in 2024 alone). API calls firing on every component mount with no caching. Hardcoded CORS wildcards.&lt;/p&gt;

&lt;p&gt;The pattern is always the same: AI picks the shortest path to "it works." The shortest path is almost always the least secure path.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did about it
&lt;/h2&gt;

&lt;p&gt;I built a GitHub Action that runs on every PR. It checks for the patterns that AI loves to generate — the ones that work but shouldn't ship.&lt;/p&gt;

&lt;p&gt;It's not magic. It's pattern matching with Semgrep. Same code always gets the same result. No AI involved in the scanning, ironically.&lt;/p&gt;

&lt;p&gt;Setup is one YAML file:&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VibeSafe&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vibesafeio/vibesafe-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It posts a comment on your PR with what it found, where it found it, and how to fix it. If you use an AI coding assistant, you can copy the fix suggestions and paste them right back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;p&gt;I want to be honest about this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can't catch business logic bugs. If your auth flow is conceptually wrong, no pattern matcher will know.&lt;/li&gt;
&lt;li&gt;It's static analysis. It reads code, it doesn't run your app.&lt;/li&gt;
&lt;li&gt;It won't catch everything. It catches the common stuff — the stuff AI generates over and over.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I'm sharing this
&lt;/h2&gt;

&lt;p&gt;I'm not a security expert. That's exactly why I needed this. If you're vibe coding and shipping without a second look at what the AI wrote, you might want to at least know what's in there.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/vibesafeio/vibesafe-action" rel="noopener noreferrer"&gt;https://github.com/vibesafeio/vibesafe-action&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's free, open source, no account needed. If you try it and it catches something weird, I'd genuinely like to hear about it.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>security</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
