<?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: Domenic Wehkamp</title>
    <description>The latest articles on DEV Community by Domenic Wehkamp (@salta1414).</description>
    <link>https://dev.to/salta1414</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%2F3703369%2F57621895-a73c-4922-83fc-89617c42b54f.png</url>
      <title>DEV Community: Domenic Wehkamp</title>
      <link>https://dev.to/salta1414</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salta1414"/>
    <language>en</language>
    <item>
      <title>How I detect typosquatting attacks before npm install runs</title>
      <dc:creator>Domenic Wehkamp</dc:creator>
      <pubDate>Mon, 12 Jan 2026 23:09:17 +0000</pubDate>
      <link>https://dev.to/salta1414/how-i-detect-typosquatting-attacks-before-npm-install-runs-2e78</link>
      <guid>https://dev.to/salta1414/how-i-detect-typosquatting-attacks-before-npm-install-runs-2e78</guid>
      <description>&lt;h1&gt;
  
  
  How I detect typosquatting attacks before npm install runs
&lt;/h1&gt;

&lt;p&gt;Last week I published &lt;a href="https://sapo.salta.world" rel="noopener noreferrer"&gt;Sapo&lt;/a&gt;, a pre-install security scanner. Today I want to show you exactly HOW it detects one of the most common attacks: &lt;strong&gt;typosquatting&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is typosquatting?
&lt;/h2&gt;

&lt;p&gt;You want to install &lt;code&gt;lodash&lt;/code&gt;. You type fast. You accidentally type &lt;code&gt;lodahs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Congratulations, you just installed malware.&lt;/p&gt;

&lt;p&gt;Attackers register packages with names similar to popular ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lodahs&lt;/code&gt; instead of &lt;code&gt;lodash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;axois&lt;/code&gt; instead of &lt;code&gt;axios&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reacct&lt;/code&gt; instead of &lt;code&gt;react&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;expresss&lt;/code&gt; instead of &lt;code&gt;express&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fake packages often contain the REAL package as a dependency (so everything seems to work), plus a little extra code that steals your credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  The detection algorithm
&lt;/h2&gt;

&lt;p&gt;Here's the actual logic Sapo uses:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Levenshtein Distance
&lt;/h3&gt;

&lt;p&gt;First, we calculate how "close" the package name is to known popular packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;levenshtein_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Returns the number of single-character edits needed&lt;/span&gt;
    &lt;span class="c1"&gt;// to transform string a into string b&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the distance is 1-2 characters, that's suspicious.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Common typo patterns
&lt;/h3&gt;

&lt;p&gt;We check for patterns humans actually make:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transposed letters: &lt;code&gt;axois&lt;/code&gt; → &lt;code&gt;axios&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Missing letters: &lt;code&gt;expres&lt;/code&gt; → &lt;code&gt;express&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Double letters: &lt;code&gt;expresss&lt;/code&gt; → &lt;code&gt;express&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Adjacent keyboard keys: &lt;code&gt;reacy&lt;/code&gt; → &lt;code&gt;react&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Popularity comparison
&lt;/h3&gt;

&lt;p&gt;Here's the key insight:&lt;/p&gt;

&lt;p&gt;If you're trying to install a package with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;47 downloads&lt;/li&gt;
&lt;li&gt;Name similar to a package with 40 million downloads&lt;/li&gt;
&lt;li&gt;Created last week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's almost certainly malicious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example detection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;lodahs

  &lt;span class="o"&gt;[&amp;gt;]&lt;/span&gt; Scanning: lodahs@1.0.0
  &lt;span class="o"&gt;[!]&lt;/span&gt; BLOCKED: Typosquatting detected

      Similar to: lodash
      - lodash: 337,000,000 downloads
      - lodahs: 47 downloads

      Levenshtein distance: 1

  Installation cancelled.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real &lt;code&gt;lodash&lt;/code&gt; has 337 million downloads. The fake &lt;code&gt;lodahs&lt;/code&gt; has 47.&lt;/p&gt;

&lt;p&gt;That ratio is a massive red flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why pre-install matters
&lt;/h2&gt;

&lt;p&gt;Most security tools scan AFTER installation. But by then, the &lt;code&gt;postinstall&lt;/code&gt; script has already run.&lt;/p&gt;

&lt;p&gt;Sapo intercepts the command BEFORE npm even starts downloading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You type: npm install lodahs
          ↓
Sapo intercepts
          ↓
API check: is "lodahs" safe?
          ↓
Response: TYPOSQUATTING DETECTED
          ↓
Installation blocked
          ↓
npm never runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your machine stays clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://sapo.salta.world/install.sh | bash

&lt;span class="c"&gt;# Restart terminal, then try:&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;lodahs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see the warning before anything gets installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;I'm working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ML-based anomaly detection&lt;/li&gt;
&lt;li&gt;Sandbox analysis&lt;/li&gt;
&lt;li&gt;VS Code extension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have ideas for what to detect next, let me know in the comments!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Salta1414/sapo-cli" rel="noopener noreferrer"&gt;github.com/Salta1414/sapo-cli&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://sapo.salta.world" rel="noopener noreferrer"&gt;sapo.salta.world&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>I built a pre-install security scanner because npm install scared me</title>
      <dc:creator>Domenic Wehkamp</dc:creator>
      <pubDate>Sat, 10 Jan 2026 02:36:56 +0000</pubDate>
      <link>https://dev.to/salta1414/i-built-a-pre-install-security-scanner-because-npm-install-scared-me-3fp</link>
      <guid>https://dev.to/salta1414/i-built-a-pre-install-security-scanner-because-npm-install-scared-me-3fp</guid>
      <description>&lt;h1&gt;
  
  
  I built a pre-install security scanner because npm install scared me
&lt;/h1&gt;

&lt;p&gt;Last month, I ran &lt;code&gt;npm install&lt;/code&gt; on a project and realized something terrifying: I had no idea what code was about to execute on my machine.&lt;/p&gt;

&lt;p&gt;Sure, we've all heard about supply chain attacks. The &lt;a href="https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident" rel="noopener noreferrer"&gt;event-stream incident&lt;/a&gt;, the &lt;a href="https://github.com/niceguys-online/cybersecurity-advisories/blob/main/advisories/2021/npm-ua-parser-js-malware.md" rel="noopener noreferrer"&gt;ua-parser-js malware&lt;/a&gt;, the countless typosquatting packages stealing credentials.&lt;/p&gt;

&lt;p&gt;But we still run &lt;code&gt;npm install&lt;/code&gt; blindly. Every. Single. Day.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Sapo&lt;/strong&gt; - a CLI tool that scans packages &lt;em&gt;before&lt;/em&gt; they touch your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When you run &lt;code&gt;npm install axios&lt;/code&gt;, here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;npm downloads the package&lt;/li&gt;
&lt;li&gt;npm runs &lt;code&gt;preinstall&lt;/code&gt; scripts&lt;/li&gt;
&lt;li&gt;npm runs &lt;code&gt;postinstall&lt;/code&gt; scripts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're already compromised&lt;/strong&gt; if it was malicious&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the time you realize something is wrong, the damage is done. Your &lt;code&gt;.env&lt;/code&gt; file, your SSH keys, your AWS credentials - all potentially exfiltrated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;Sapo wraps your package manager and intercepts install commands:&lt;/p&gt;

&lt;p&gt;$ npm install lodahs  # typo - this is a malicious package!&lt;/p&gt;

&lt;p&gt;[&amp;gt;] Scanning: &lt;a href="mailto:lodahs@1.0.0"&gt;lodahs@1.0.0&lt;/a&gt;&lt;br&gt;
  [!] BLOCKED: Typosquatting detected&lt;br&gt;
      Similar to: lodash (337M downloads)&lt;/p&gt;

&lt;p&gt;Installation cancelled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Salta1414/sapo-cli" rel="noopener noreferrer"&gt;github.com/Salta1414/sapo-cli&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://sapo.salta.world" rel="noopener noreferrer"&gt;sapo.salta.world&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
      <category>security</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
