How to Check for Malware in your NPM Packages
Software Engineers love to build things. Solving issues and building tooling is second nature to us. For a lot of beginning software engineers, the process of reinventing the wheel is important both to stretch technical abilities as well as gain knowledge on key aspects of software development.
As you move to bigger projects with stricter deadlines it becomes necessary to use prebuilt solutions to handle common design features or solve common problems. These solutions come in the form of prepackaged software files. Each programming language has its own name for these units of software, but JavaScript calls them packages.
Packages are self contained groups of logic that allow us to use and implement functions for common features. This could be something as simple as a set of currency formatting functions or as complex as an integration testing suite. Packages come in all shapes and sizes, and anyone can develop and deploy them for community use.
This last aspect is great as a vibrant open source community leads to new and better ways to solve problems. Many hands make light work and with organizations such as NPM (node package manager) overseeing the hosting and sharing of software packages, solving any problem is just a few clicks away.
While having these packages be open source is great for community solutions, does the ability for anyone to publish packages put developers at risk? Unfortunately, yes. Any community that relies on trust is susceptible to abuse, NPM does a good job of steering its users towards safe packages, but can’t catch everything. In this article I’d like to take their steps further by outlining what potential malicious code is, how it is hidden in plain sight and ways to avoid compromising your projects.
Targeted Mistypes and Spelling Exploits
The command line is a very powerful tool, especially when you pair it with a command line tool such as npm. With the npm command line tool you can download, update and remove npm packages for your project with one line commands. Whatever you do on the command line should be reflected in your package.json file. This is what you may share on Github with others who would like to work on your code from their local devices.
With the ease of use for online package install commands comes some issues. We all make mistakes when typing. Sure, software engineers may have a higher affinity for misspellings as our job is to make things work, not write elegant copy. These misspellings aren’t always due to not knowing the correct spelling. Oftentimes an errant keystroke or sticky key may lead us to add an extra “i” or insert a space between a leading flag character like “- i.” These mistakes seem small, but can have huge effects.
A mysterious npm package appeared in 2017 that was simply called “-“. What does this package do? Absolutely nothing. At the time this package was investigated, it was already a dev dependency for over 50 other packages and had over 720,000 downloads. That’s a lot of activity for a package that offers no value.
What is the reason for this package existing? The package’s author claims that this package was created to test the accepted names for npm packages. Though the author claims no harm in creating this package, and plans to use it as a package that would cleanup other single character or mistyped package command names, it shows the potential issues with command line installs.
No one is perfect, but the command line can not intuit what you mean to type and prevent you from installing bad packages. Bad faith actors know this and pollute npm with malicious packages which slightly alter the names of popular packages. This way they can potentially profit off a slip of a finger or an extra key stroke.
The only ways to prevent this from happening to you is to double check your install commands before pressing enter on the command line and always verify that the package list in your package.json doesn’t have any unwanted dependencies. We can’t always be perfect, but we can always be careful.
Malicious Dependencies
The beauty of packages is their ability to offer prebuilt solutions to software developers to save time and potential bugs. Not all packages are self contained as some are referential, leveraging other packages to build out complex functionality. Packages you bring into your project are dependencies that your project relies on. Packages themselves can leverage packages leading to a graph of dependencies.
Where’s the issue? If you are picking single level packages to integrate into your project you can ensure that you get exactly what you want, and that it is safe. What happens if one of your packages pulls in 10 dependencies of its own, and one of them is malicious? Then you’re in trouble:
Luckily for community generated, open source packages there are a lot of eyes to keep the source code honest and safe. While you’re never fully safe from someone slipping something malicious into code, using active (check the contributors on Github) and well maintained and starred npm packages should be pretty safe.
** Don’t base npm package safety off of npm downloads as this stat can be heavily gamed by cron jobs for general downloads. As of writing npm doesn’t filter by IP for “unique” downloads. See the article “I exploited npm downloads” linked in the notes below. **
What Kind of Threats do Malicious Packages Pose?
What kind of risks are we talking about with malicious npm packages? To start, depending on your project’s configuration, npm packages are great conduits to steal credentials and ENV variables. The malicious code can stay dormant for local development until the app is launched in production at which point it can scrape your .env files and transmit it to a third party.
Along with stealing ENV variables, these malicious packages can install backdoors in apps, convert user devices to botnet bots, hijack crypto wallets, read and relay user inputs and steal user device information.
Non Threatening Malicious Developers
An aside from our topic, but something to keep in mind: not all malicious packages are developed and submitted by bad actors. The University of Minnesota was recently banned from contributing to the Linux kernel project (one of the largest open source software projects) for allegedly committing malicious code.
White hat hackers get permission to test security, black hat hackers don’t tell you that they’ve tested security or what they’ve taken and gray hat hackers test then ask for forgiveness. The University of Minnesota allegedly acted as a gray hat, but overstepped what was acceptable by trying to get security exploits published to the distributed Linux kernel.
A major research university, and highly respected engineering school, allegedly pushed up code that put an entire community at risk. Remember this next time you blindly trust an open source project without verifying that all security risks including dependencies have been checked.
How to Report Malicious and Suspicious Code to NPM
If you find malware in your npm package, or a package that you use, no worries. NPM has a very helpful form for submitting malware reports. From the package page you can click on the red “Report malware” button to be taken to a form. On this form you can report the security issue, the package name, version in contest and any other information you may find useful.
From here NPM can review the package, remove any offending code and determine which parties are at fault and need further followup. It couldn’t be an easier process!
Conclusion
I hope that this article has helped you better understand how to research potential packages for your projects and avoid any malicious products. Trusting but verifying is an important part of successfully harnessing the power of open source software and I hope you now have the tools and knowledge to verify your own project’s integrations.
Notes
https://iamakulov.com/notes/npm-malicious-packages/
https://docs.npmjs.com/reporting-malware-in-an-npm-package
https://dev.to/andyrichardsonn/how-i-exploited-npm-downloads-and-why-you-shouldn-t-trust-them-4bme