<?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: fitz kk</title>
    <description>The latest articles on Forem by fitz kk (@fitz_kk_6c2bacfecba314514).</description>
    <link>https://forem.com/fitz_kk_6c2bacfecba314514</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%2F3682466%2F8d1599a7-d084-477f-983b-11d47acf62d9.png</url>
      <title>Forem: fitz kk</title>
      <link>https://forem.com/fitz_kk_6c2bacfecba314514</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/fitz_kk_6c2bacfecba314514"/>
    <language>en</language>
    <item>
      <title>How I discovered 16.7% of my Stripe revenue was bypassing fraud checks (and built a fix)</title>
      <dc:creator>fitz kk</dc:creator>
      <pubDate>Sun, 28 Dec 2025 10:21:45 +0000</pubDate>
      <link>https://forem.com/fitz_kk_6c2bacfecba314514/how-i-discovered-167-of-my-stripe-revenue-was-bypassing-fraud-checks-and-built-a-fix-530m</link>
      <guid>https://forem.com/fitz_kk_6c2bacfecba314514/how-i-discovered-167-of-my-stripe-revenue-was-bypassing-fraud-checks-and-built-a-fix-530m</guid>
      <description>&lt;p&gt;Last week, a friend's SaaS account ($50k ARR) was suddenly &lt;strong&gt;banned&lt;/strong&gt; by Stripe due to card testing attacks.&lt;br&gt;
We were confused because he had &lt;strong&gt;Stripe Radar&lt;/strong&gt; enabled. We thought he was safe.&lt;/p&gt;

&lt;p&gt;So, being a developer, I dug into his transaction logs. I discovered a default configuration "blind spot" that I believe affects 30%+ of Indie Hackers.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Technical Root Cause
&lt;/h2&gt;

&lt;p&gt;I analyzed the JSON payloads of the fraudulent transactions. They all shared one specific pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"billing_details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"city"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"line1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payment_method_details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"address_line1_check"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"address_postal_code_check"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue: If you use Stripe's default Checkout (especially with Apple Pay or Link), it often defaults to not collecting the billing address to maximize conversion rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Consequence:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No Address = No AVS:&lt;/strong&gt; Stripe cannot perform an AVS (Address Verification Service) check.&lt;/p&gt;

&lt;p&gt;Radar Blindness: Most default Radar rules rely on location mismatches (e.g., "IP Address doesn't match Billing Address"). If there is no Billing Address, these rules are skipped.&lt;/p&gt;

&lt;p&gt;I call these &lt;strong&gt;"Ghost Transactions"&lt;/strong&gt;. They are invisible to your primary defense layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auditing My Own Account
&lt;/h3&gt;

&lt;p&gt;Terrified, I scripted a quick audit of my own Stripe history. The result? 16.7% of my transactions were "Ghost Transactions".&lt;/p&gt;

&lt;p&gt;I was essentially "flying blind" on a quarter of my revenue. If a card tester targeted me, Radar wouldn't stop them until the disputes started rolling in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fix (Manual vs Automated)
&lt;/h3&gt;

&lt;p&gt;Option 1: Manual Check Go to your Stripe Dashboard -&amp;gt; Payments. Hover over the card details. If you see "No address provided" and AVS checks show "Unavailable" or "Unchecked", you are exposed.&lt;/p&gt;

&lt;p&gt;Option 2: Automated Audit Tool Since I didn't want to check this manually every week, I built a "Terminal-style" tool to scan for this specific vulnerability automatically.&lt;/p&gt;

&lt;p&gt;It's called &lt;a href="https://ghostaudit.io/" rel="noopener noreferrer"&gt;GhostAudit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Audit:&lt;/strong&gt; Scans your last 100 transactions via a Restricted Read-Only Key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visualize:&lt;/strong&gt; Shows your exact "Ghost Rate" (risk exposure).&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix: Generates the custom Radar rules to plug the hole.
&lt;/h3&gt;

&lt;p&gt;👉 Check your risk exposure here: &lt;a href="https://ghostaudit.io/" rel="noopener noreferrer"&gt;ghostaudit.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(First 100 scans are free. Don't wait for the ban hammer to verify your settings.)&lt;/p&gt;

</description>
      <category>stripe</category>
      <category>security</category>
      <category>saas</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
