<?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: Khushi Trivedi</title>
    <description>The latest articles on DEV Community by Khushi Trivedi (@trivedi-khushi).</description>
    <link>https://dev.to/trivedi-khushi</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%2F1358087%2Fa2429c02-d5b4-4b76-8b99-59ddb2039c8d.png</url>
      <title>DEV Community: Khushi Trivedi</title>
      <link>https://dev.to/trivedi-khushi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/trivedi-khushi"/>
    <language>en</language>
    <item>
      <title>The 60-Second Check Before Every npm install</title>
      <dc:creator>Khushi Trivedi</dc:creator>
      <pubDate>Mon, 19 Oct 2026 15:32:41 +0000</pubDate>
      <link>https://dev.to/trivedi-khushi/the-60-second-check-before-every-npm-install-2bg</link>
      <guid>https://dev.to/trivedi-khushi/the-60-second-check-before-every-npm-install-2bg</guid>
      <description>&lt;h2&gt;
  
  
  One wrong package name can run attacker code on your laptop or CI
&lt;/h2&gt;

&lt;p&gt;Honestly, I'd say &lt;code&gt;npm install&lt;/code&gt; is the riskiest five seconds of your day now that typosqatting is so common. It's the potential moment a attacker's code gets a chance to run on your laptop or your CI runner.&lt;/p&gt;

&lt;p&gt;This is not theoretical anymore. It has happened several time, at a huge scale! Some incide&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;2017, The Slovak National Security Office&lt;/strong&gt; flagged ten fake Python packages. One fake package was &lt;code&gt;urllib&lt;/code&gt;,instead of &lt;code&gt;urllib3&lt;/code&gt;.&lt;br&gt;
They also collected the system's data! &lt;a href="https://news.sophos.com/en-us/2017/09/19/pypi-python-repository-hit-by-typosquatting-sneak-attack/" rel="noopener noreferrer"&gt;news link&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;npm's official record listed 13 releases of a fake package&lt;/strong&gt; called &lt;code&gt;crossenv&lt;/code&gt; for the real pkg &lt;code&gt;cross-env&lt;/code&gt;. Funfact if you today run &lt;code&gt;npm view crossenv&lt;/code&gt;, it returns &lt;code&gt;0.0.2-security&lt;/code&gt;. This is apparantly a placeholder npm put in its place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;19.7% AI generated code samples had package names that doesn't exist.&lt;/strong&gt; Yes, in 2025 USENIX Security study checked 2.23 million AI-generated code samples. If I were an atatcker, I'd register those names and wait. This is called &lt;a href="https://labs.cloudsecurityalliance.org/research/csa-research-note-slopsquatting-ai-supply-chain-20260419/" rel="noopener noreferrer"&gt;slopsquatting.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After reading about these attacks, I'd the first thing is to have my own investigation. Here are my findings. Enjoy the blog further:&lt;/p&gt;

&lt;h2&gt;
  
  
  How to confirm a package is the one you meant, step by step
&lt;/h2&gt;

&lt;p&gt;This is for developers, SREs, DevOps engineers, and the people who review their pull requests. Run these before you add a package you have not used before:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Exact spelling and ecosystem&lt;/strong&gt;&lt;br&gt;
Read the name letter by letter against the project's own docs. Then ask the registry if it exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env name version
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip index versions requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;A missing name returns &lt;code&gt;E404&lt;/code&gt; on npm, or &lt;code&gt;No matching distribution found&lt;/code&gt; on pip. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Publisher and repo link&lt;/strong&gt;&lt;br&gt;
Check who owns the package. Then check where it says its code lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env maintainers repository.url
&lt;span class="c"&gt;# maintainers = 'kentcdodds &amp;lt;me@kentcdodds.com&amp;gt;'&lt;/span&gt;
&lt;span class="c"&gt;# repository.url = 'git+https://github.com/kentcdodds/cross-env.git'&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypi.org/pypi/requests/json | python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import sys,json; i=json.load(sys.stdin)['info']; print(i['version'], i['project_urls'])"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** 3. The Package age and publish history **&lt;/p&gt;

&lt;p&gt;You can use this to check about the package's record-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env time.created time.modified
&lt;span class="c"&gt;# time.created = '2015-10-01T23:19:27.453Z'&lt;/span&gt;

npm view cross-env &lt;span class="nb"&gt;time

&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypi.org/pypi/requests/json | python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import sys,json; r=json.load(sys.stdin)['releases']; print(min(f['upload_time_iso_8601'] for v in r.values() for f in v))"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The red flags would be spotted if: (a) it's been created recently, but has a famous name (b)there's a new maintainer on an old package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Weekly downloads vs. the real project&lt;/strong&gt;&lt;br&gt;
Another interesting thing that you can do while patrolling is to compare the lookalike with the project it resembles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.npmjs.org/downloads/point/last-week/cross-env
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypistats.org/api/packages/requests/recent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Low count, new package =&amp;gt; normal. &lt;br&gt;
Low count, fake package for a famous name =&amp;gt; suspicious.&lt;/p&gt;

&lt;p&gt;For your example: &lt;code&gt;pypistats&lt;/code&gt; excludes known mirrors and updates once a day. (Ref: &lt;a href="https://pypistats.org/api/" rel="noopener noreferrer"&gt;PyPI Stats API&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Install scripts&lt;/strong&gt;&lt;br&gt;
Here's my observation. Many legitimate packages have a script. I understood this from the hidden install scripts are &lt;a href="https://snyk.io/blog/sha1-hulud-npm-supply-chain-incident/" rel="noopener noreferrer"&gt;how the September 2025 Shai-Hulud worm ran its code&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view esbuild scripts.postinstall
&lt;span class="c"&gt;# node install.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Lockfile diff&lt;/strong&gt;&lt;br&gt;
One new dependency can pull in many. As a developer, you must never skip reading what changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff origin/main &lt;span class="nt"&gt;--&lt;/span&gt; package-lock.json

&lt;span class="c"&gt;# only new install scripts&lt;/span&gt;
git diff origin/main &lt;span class="nt"&gt;--&lt;/span&gt; package-lock.json | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^\+.*"hasInstallScript"'&lt;/span&gt;

&lt;span class="c"&gt;# for a version bump, see what changed in the code&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pkg@1.0.0 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pkg@1.0.1 &lt;span class="nt"&gt;--diff-name-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for names you did not expect, and any added "hasInstallScript": true. For Python, do the same with git diff requirements.txt. &lt;a href="https://docs.npmjs.com/cli/v11/commands/npm-diff" rel="noopener noreferrer"&gt;npm diff docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the limitations for these six checks
&lt;/h2&gt;

&lt;p&gt;They're merely the checks, but do not really make any install "safe". These are the following limitations:&lt;/p&gt;

&lt;p&gt;• A real package published by a real maintainer whose account was compromised will pass all six checks.&lt;br&gt;
• A lockfile poisoned before anyone noticed will look normal in a diff.&lt;br&gt;
• Malicious code that lives in a package's runtime JavaScript, not in an install script, is not stopped by ignore-scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resouces
&lt;/h2&gt;

&lt;p&gt;I came across this blog- &lt;a href="https://www.cleanstart.com/blogs/what-is-typosquatting-attacks-examples-and-ai-risks" rel="noopener noreferrer"&gt;What Is Typosquatting? Attacks, Examples, and AI Risks.&lt;/a&gt; by CleanStart.&lt;/p&gt;

&lt;p&gt;In this, you can checkout the for the org-level version of this checklist. &lt;/p&gt;

&lt;p&gt;It's also my first blog here. Please share your love in comments!❤️&lt;/p&gt;

</description>
      <category>typosquatting</category>
      <category>cybersecurity</category>
      <category>npm</category>
      <category>containersecurity</category>
    </item>
  </channel>
</rss>
