How to Conquer Remote Code Execution (RCE) in npm
Table of Contents
Recently, there have been some remote code execution (RCE) attacks that included just a single line of well-built code that can run a remote shell. Let’s take a look at why and how these attacks work, why npm is particularly susceptible, what could happen if they get into machines, and how to detect and fix them.
Why is npm susceptible to RCE?
npm is particularly susceptible to RCE attacks because it’s the world’s largest software registry, and because the registry design contains numerous flaws that make it easy for individuals to publish malicious code unnoticed. As npm doesn’t automatically check for vulnerabilities or prevent developers and users from uploading and downloading insecure packages, it is a prime target for attackers. To give one example, a malicious actor can just create a connection to a remote host to establish a reverse shell.
Moreover, since the npm registry never runs the code autonomously, both benign and malign code is only activated when being used by end-users. Think of npm as similar to Dropbox. Dropbox won’t open, run, and read your files and work with them unless you are working on them. The same applies to npm. npm and other registries give you the space to show your projects and share open source code with other users, but not the ability to run them. This means that the malicious package essentially lies dormant until somebody unknowingly installs the package, thus exposing their code to attack when they use affected packages.
Why is RCE such a threat?
When you install an RCE package, you give away all the permissions of the current user. Most users don’t use isolated environments, so that means with each installation, you’re giving abstract permission for universal access to your machine. Permissions are granted at the time of installation. When you install dependencies, you grant permissions, making it quite convenient for attackers to access every line of code. When a connection is established, they have a full remote shell, and they can do what they want with it. Just imagine giving away your login and password to anyone on the internet and allowing them to access your computer from their machine, to do whatever they want. That’s the level of risk you run.
Many users are either unaware of this point of weakness, or in the interests of speed, choose to ignore it. Users either don’t know or don’t care about these risks, because they expect a level of security from npm and other registries that isn’t automatically there. Unlike app stores like Google Play or equivalents, where all packages are scanned and certified, open source spaces don’t have the resources to do that. Unfortunately, users often erroneously assume that they do.
How do RCE cases commonly behave and operate?
Broadly speaking, RCE attacks fall into one of three different categories.
- Firstly, RCE attacks are mostly used for data exploration, opening the door for malicious actors to steal data such as credentials, research information such as intellectual property, hostname center details, and Secure Shell (SSH) keys that authenticate and establish encrypted communication channels over the internet between clients and remote machines. Ethical hackers use it to prove that compromises have happened.
- The second common scenario is cryptocurrency mining. For example, at the time of writing, a very busy attacker uploaded roughly 1,200 malicious packages containing cryptocurrency mining tools to npm over the course of 48 hours. Malicious hackers use others’ existing resources to mine and steal cryptocurrency. Alternatively, they use RCE to upload cryptocurrency mining tools into packages on npm. Usually, these are easy to detect and notice, because they’re big pieces of software and you can get binaries to scan and analyze them.
- In the third case, RCE works within cryptocurrency exchanges to steal savings from accounts by copying and pasting wallet IDs and replacing them. A script runs in the background that checks where there’s a crypto wallet on the clipboard and replaces it.
What should be done to identify and remediate RCE exploits/flaws?
There isn’t one solution to identify and remediate all exploits, but there are a few things you can do, from both the registry and end-user perspective.
On the registry side. implementing user grading is one tactic to reduce incidents. User grading limits how many packages users can upload, and you can benchmark and score against predetermined limits. This provides a degree of scrutiny, but it obviously won’t fix cases where regular users with better gradings and higher limits are free to upload more packages, some of which may pose risks. It will also not prevent account takeover (ATO) attacks.
Scanning code is another method. Although npm has been talking about automatic scanning systems, they haven’t yet announced any solution of that nature, so it’s up to the user to implement such a system.
On the end-user side, you could stop updating dependencies. Package versions are supposed to be immutable, so that you know how they will always behave. When there’s an update and a new version is needed, you’re supposed to replace the old version with the new. Nevertheless, if you lock all your dependencies, you put your software in a semi-maintenance mode. There are also bug fixes and CVEs that you may want to patch with updates.
You can also try blocking all the install hooks with npm, but this may cause some code to stop working because you may block legitimate cases. You may compile extensions or download some third-party binaries. This is bad because all the package content should already be in the package.
Or you can try implementing your own security scanning. Some users have attempted to do this by downloading packages and scanning them all with antivirus software. The problem with this is that you may miss many cases. That’s because antivirus software is good with binaries and mainly with binaries that it knows. So, you have signatures for certain behaviors of packages that are already running, and only then does the antivirus software kick in. They don’t scan scripts or text-based software.
Unfortunately, the majority of attacks do not presently use binary files. They use text-based code that can be obfuscated because the antivirus or the operating system doesn’t detect it. The code activates any malicious intent once it has been imported and installed. In fact, it’s easy for malicious code to escape the detection of traditional antivirus software, and sneak into your code base. That’s the reason why software supply chain attacks have become so widespread.
Preventing RCE in npm and RubyGems with Mend
Mend Supply Chain Defender is specifically designed to prevent malicious open source software from entering your code base. When it comes to RCE attacks in npm, Mend Supply Chain Defender can rapidly detect newly released packages and within around 15 minutes it picks them up, scans them, and grades them for risk. If a package exceeds a graded risk threshold, the tool blocks it so that it can be manually inspected, and its risk mitigated.
Mend Supply Chain Defender has a very thorough scoring system that prevents you from using packages that haven’t yet been analyzed. Only when either an automatic system or a manual review gives you a positive result for usage, can the package version be downloaded. Even then, it won’t immediately be installed, and downloading can be blocked if there is any doubt. Whether you’re using our plugins or using the artifactory integration that we recently released, Mend Supply Chain Defender stops suspect packages from being downloaded.
Furthermore, when you use our plug-ins, you can create your own custom rules and thresholds to manage which packages and downloads you will permit. You can create policies that can be more or less restrictive, tailored precisely to the needs of your organization and your developers. Learn more about how you can mitigate your open source supply chain risks with Mend Supply Chain Defender, here.