• 5 min read

NPM Supply Chain Under Attack

NPM Supply Chain Under Attack

An in-depth look at recent vulnerabilities in the NPM ecosystem and how to protect your projects.

NPM Supply Chain Security Vulnerabilities Open Source Shai Hulud

Shai Hulud: NPM Supply Chain Under Attack

Already in the middle of 2025, the NPM ecosystem has faced a significant supply chain attack - named “Shai Hulud” - that has exposed vulnerabilities in numerous popular packages. This attack has been detremental as it was a self-replicating malware that infected over 25,000 repositories by exploiting the trust developers place in widely-used NPM packages.

Shai Hulud operated by injecting malicious code into popular packages, which then propagated to any project that depended on them. The malware was designed to steal sensitive information, including environment variables and configuration files on post-install scripts execution. This sensitive data was then published to a public repository on GitHub named “Shai Hulud” under the victim’s account, exposing it to potential misuse. And the worst part: The malware did not stop at stealing data - it would use the npm tokens found in the environment to inject the malicious code into other packages maintained by the same compromised developer, further spreading the infection.

This self-replicating nature has proven to be particularly effective in spreading the malware across the NPM ecosystem and exposed a fundamental problem in the ecosystem. We use too many third-party dependencies, which are often not properly audited or maintained due to lack of time or resources. And don’t get me wrong - I mean no disrespect to open source maintainers. They do an incredible job maintaining these packages, often for free. However, the reality is that open source is heavily underfunded, such that we simply cannot expect open source maintainers to properly secure and audit all the packages we depend on. They often have a real job, a family, and other responsibilities - and their open source work is just a side project. Expecting them to properly secure and audit all the packages we depend on is unrealistic and straight up unfair. Never the less, this is the reality we are facing and the entire NPM ecocsystem is built on top of hundreds and thousands of these open source packages.

There is no easy solution to this problem as it is systemic and requires a collective effort from the entire community. However, looking at the problem at heart, I believe that the core issue is that we should not rely on packages maintained by individuals or small teams for critical functionality in our applications. Instead, we should rely on packages maintained by larger organizations or foundations that have the resources and incentives to properly secure and audit their packages. These organizations are more likely to have dedicated security teams, proper funding, and a vested interest in maintaining the security and integrity of their packages. Look at React - maintained by Meta, or Angular - maintained by Google, Typescript - maintained by Microsoft, Docker - maintained by Docker Inc. These organizations have the resources and incentives to properly secure and audit their packages, making them a more reliable choice for critical functionality in our applications. All Big Tech companies have a vested interest in maintaining the security and integrity of their packages and the packages they depend on, as their reputation and business depend on it. Therefore, I would hope to see more Big Tech companies taking responsibility for maintaining critical open source packages in the future. They have the resources, money, expertise, and incentives to do so, and it would benefit the entire ecosystem.

But, that’s just my two cents and will likely never happen…

How to Protect Your Projects

In the meantime, here are some steps you can take to protect your projects from similar supply chain attacks:

Usually, these malicious packages are detected rather quickly and removed from the NPM registry. However, there is a delay between the initial publication of the malicious package and its detection and removal. During this time, your project may have already been compromised if you installed the malicious package. So here are three tips to protect your projects:

1. Avoid npm install

Whenever you run npm install, you are downloading and executing code from third-party packages, which may contain malicious code. You never know what code will be downloaded and executed through post-install scripts. Therefore, avoid running npm install unless absolutely necessary.

Instead, consider using lock files (package-lock.json or yarn.lock) to ensure that you are installing the exact versions of packages that you have audited and trust. Additionally, consider using tools like npm ci, which installs packages based on the lock file without modifying it, reducing the risk of introducing new vulnerabilities.

The reason this is safer is that lock files pin the exact versions of packages and their dependencies, ensuring that you are installing the same code that you have installed previously. On the other hand, running npm install without a lock file may result in installing newer versions of packages, especially when you use version ranges in your package.json file (e.g., ^1.0.0 or ~1.0.0). These newer versions may contain vulnerabilities or malicious code that were not present in the versions you have previously audited and trusted.

2. Pin Dependency Versions

Sometimes, you must run npm install to add new packages or update existing ones. To avoid risking the introduction of malicious code, always pin the exact versions of packages in your package.json file. Avoid using version ranges that allow for automatic updates to newer versions. For example, instead of using "lodash": "^4.17.21", use "lodash": "4.17.21".

This will make it less likely that you will inadvertently install a malicious version of a package when running npm install. Additionally, consider using tools like npm audit to regularly check for known vulnerabilities in your dependencies and update them accordingly.

However, this won’t protect you entirely, as even specific versions of packages can install new peer dependencies with npm install that may contain vulnerabilities or malicious code. Think of a package that has a dependency or a peer dependency that is not pinned to a specific version. When you run npm install, it may install the latest version of that dependency, which could contain vulnerabilities or malicious code.

3. Use PNPM’s minimumReleaseAge flag

If you are using PNPM as your package manager, consider using the minimumReleaseAge flag when installing packages. This flag allows you to specify a minimum age for package releases, preventing the installation of newly published packages that may not have been thoroughly vetted by the community yet.

By setting a minimum release age, you can reduce the likelihood of installing packages that may contain vulnerabilities or malicious code.

Conclusion

The NPM supply chain attack “Shai Hulud” has exposed vulnerabilities in the NPM ecosystem and highlighted the risks of relying on third-party packages. To protect your projects, avoid running npm install unless necessary, pin dependency versions in your package.json file, and consider using PNPM’s minimumReleaseAge flag. By taking these steps, you can reduce the risk of introducing malicious code into your projects and help ensure the security and integrity of your applications.

This attack serves as a reminder of the importance of supply chain security and the need for collective efforts to improve the security of the open source ecosystem.

Stefan Haas

Stefan Haas

Senior Software Engineer at Microsoft working on Power BI. Passionate about developer experience, monorepos, and scalable frontend architectures.

Comments

Join the discussion and share your thoughts!