In early August, several dozens of npm packages detected malicious code. The administration of npmjs.com quickly responded to this and immediately
prepared a report on the measures taken. Later, Dominic Kundel from twilio.com shared
tips on how to find projects "infected" with similar packages. We present to your attention the story of these events.
The malicious package crossenv in the npm registry
On August 1 of this year, we, the administration of
npmjs.com , were told on
Twitter that the package, whose name was very similar to the popular
cross-env
, sends environment variables from its installation context to npm.hacktask.net. We immediately investigated and removed this package from the registry. Further study of the situation led to the detection in the registry about 40 more malicious packages.
On July 19, hacktask published a number of packages whose names were very similar to the names of popular npm packages. We call this phenomenon "typo-squatting", this is the seizure of a certain resource due to a typo. Previously, this happened mainly by accident. Several times we have seen the deliberate use of this way of naming packages, which was resorted to by authors of libraries competing with already existing packages. Now the names of the packages were chosen specifically, and this was clearly done with malicious intent. Namely, the author of the packages intended to steal data from misled users. As a result, all hacktask user packages have been removed from the registry.
')
Adam Baldwin of
Lift Security also became interested in this incident and decided to find out if there are other packages in the registry that do not belong to hacktask but contain the same code. It has a list of hashes of the contents of all public packages, which makes such studies possible. He could not find other files in the registry with the same content.
Malicious Package List
Here is a list of hacktask’s packages with their total downloads for the period from July 19 to July 31. The number of downloads of these packages increased immediately after the detection of malicious code, which was caused by the general interest in the problem. Download data before finding the problem more accurately reflects the scale of the incident. Note that about forty downloads are a typical number for any publicly available package published in the registry, as this corresponds to the number of automatic downloads on the registry mirrors. With this in mind, you can see that the real threat comes from the
crossenv
package, which scored almost 700 downloads, in second place is the
jquery.js
package. However, it also needs to be
crossenv
mind that most of the downloads are done by mirrors that requested copies of the 16 published versions of the
crossenv
package. We estimate the number of real
crossenv
installations
crossenv
about 50, perhaps even fewer.
- babelcli: 42
- cross-env.js: 43
- crossenv: 679
- d3.js: 72
- fabric-js: 46
- ffmepg: 44
- gruntcli: 67
- http-proxy.js: 41
- jquery.js: 136
- mariadb: 92
- mongose: 196
- mssql-node: 46
- mssql.js: 48
- mysqljs: 77
- node-fabric: 87
- node-opencv: 94
- node-opensl: 40
- node-openssl: 29
- node-sqlite: 61
- node-tkinter: 39
- nodecaffe: 40
- nodefabric: 44
- nodeffmpeg: 39
- nodemailer-js: 40
- nodemailer.js: 39
- nodemssql: 44
- noderequest: 40
- nodesass: 66
- nodesqlite: 45
- opencv.js: 40
- openssl.js: 43
- proxy.js: 43
- shadowsock: 40
- smb: 40
- sqlite.js: 48
- sqliter: 45
- sqlserver: 50
- tkinter: 45
If you downloaded and installed something from this list, you should immediately deactivate or change any credentials that might have been in the shell environment.
â–ŤOn the next steps to protect the registry
Publishing packages in the npm registry from hacktask’s email address is blocked. In our times, when mail can be started in two clicks with the mouse, this is not enough to keep the person behind the hacktask nickname from a new attempt to publish dangerous packages, however, we decided that this was a necessary step.
We support the Lift Security and Node Security Project in their current work on performing static analysis of public packages, but these efforts will not allow to find absolutely all problem packages. Determining whether a package contains something harmful when publishing is, of course, equivalent to a stop problem, we cannot do this.
We discuss various approaches to detecting and preventing the publication of packages whose names, either accidentally or intentionally, are made very close to the names of existing packages. There are software solutions to this problem, and we may use them to ban the publication of such packages. We use the
Smyte service to detect spam publications, and will experiment in the direction of using it to detect other types of violations of our terms of service.
How to find projects "infected" with malicious npm-packages
Here is a screenshot from Oscar Bolmsten's tweet, from which npmjs.com learned that the
crossenv
package probably steals environment variables.
Crossenv package analysisThis is especially dangerous if we take into account the fact that
environment variables can contain accounting data for various services. The problem is not limited to the
crossenv
package. We are talking about a whole set of packages. All of them are noticeable by the fact that their names resemble the names of popular modules with minor changes, like typos, such as a missing hyphen.
â–Ť Check projects for the presence of malicious packages
The packages in question were removed from the registry, however, since data theft occurs during the installation of the package, you should check to see if you have installed one of them. Ivan Akulov compiled a
list of these packages and published it in his blog. In addition, he wrote a small program that you can use to check if these packages are used in your current project:
npm ls | grep -E "babelcli|crossenv|cross-env.js|d3.js|fabric-js|ffmepg|gruntcli|http-proxy.js|jquery.js|mariadb|mongose|mssql.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv.js|openssl.js|proxy.js|shadowsock|smb|sqlite.js|sqliter|sqlserver|tkinter"
â–ŤSearch for "infected" projects on Mac and Linux
If you, like me, regularly develop under Node.js, you can have a whole set of projects that it would be good to check. I expanded the code of Ivan precisely for this reason. In particular, I used the
find
and
xargs
commands to scan all the subdirectories of the folder containing my projects. Each project is then checked using the above code. You can run the script by simply copying it to the command line:
find . -type d -maxdepth 4 -name node_modules -print0 | xargs -0 -L1 sh -c 'cd "$0/.." && pwd && npm ls 2>/dev/null | grep -E "babelcli|crossenv|cross-env.js|d3.js|fabric-js|ffmepg|gruntcli|http-proxy.js|jquery.js|mariadb|mongose|mssql.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv.js|openssl.js|proxy.js|shadowsock|smb|sqlite.js|sqliter|sqlserver|tkinter"'
I know, the code turned out rather big, so I will explain what's what.
- The script, starting with the current directory, performs a recursive search for folders named
node_modules
, using the find
. The search depth is currently limited to 4 levels of nesting, but you can change this according to the structure of your projects.
- Then it uses the
xargs
command, which executes the code for each line (that is, a directory) returned by find
.
- The code that will be executed creates a new instance of the shell, in which the following actions will be performed:
- First, the shell goes to the parent directory of the
node_modules
folder.
- Next, the name of the current directory being scanned is displayed using the
pwd
. Note that the fact that the name of the directory will be displayed does not mean that it is “infected”.
- After that,
npm ls
launched, which leads to the output of all modules installed in the project.
- Since the
npm ls
can display messages about non-existent dependencies or other errors, we redirect all messages destined for stderr
to /dev/null
(that is, simply discard them).
- All the rest is sent to
grep
to check whether there is any mention of malicious packages. If such a package is found, the program will notify you with the path to it.
â–ŤSearch for "infected" projects in Windows
If you are running Windows, here is the PowerShell script that Corey Weathers wrote. It does the same thing as the program just reviewed for Mac and Linux.
Get-ChildItem $directory -Directory -Recurse -Include "node_modules" | foreach { cd $_.FullName; cd ..; npm ls | Select-String -Pattern "babelcli|crossenv|cross-env\.js|d3\.js|fabric-js|ffmepg|gruntcli|http-proxy\.js|jquery\.js|mariadb|mongose|mssql\.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer\.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv\.js|openssl\.js|proxy\.js|shadowsock|smb|sqlite\.js|sqliter|sqlserver|tkinter"} -ErrorAction Ignore
How to understand that a malicious package was found?
This is how the screen looks when it detects a malware package. We, in this case, for demonstration purposes, were looking for an
express
package.
Red indicates a message about a malicious package found.What if a malware package is found?
In this situation, you should immediately change all the secret data that was stored in the environment variables. We are talking about, for example, passwords for access to accounts, API keys, and so on. If a vulnerability is found in a project that is being collaborated on, do not forget to alert all developers to the danger. Remember that continuous integration systems and cloud hosting also use environment variables. Therefore, if one of such projects got into production, or uses a system in which there are environment variables, take measures so that the data that could get to the attacker were useless.
â–ŤIf nothing is found, then everything is fine?
The above scripts simply check for the presence of npm-packages in projects, the danger of which we know. However, the npm ecosystem is huge, so you can’t say with certainty that there are no other dangerous packages in it. In any case, it is useful to periodically change passwords and keep valuable data carefully.
In addition, care should be taken, for example, on how services are used, the credentials of which are stored in environment variables. For example, if we are talking about an account on Twilio, suspicion should cause an unexpected jump in the number of phone calls or messages.
Results
If it turns out that you find a suspicious npm package, be sure to inform the security service of npmjs.com by writing to them at
security@npmjs.com . They investigate the situation and, if the fears are confirmed, they delete the dangerous package from the registry, and possibly several packages.
Malicious npm packages are a relatively new phenomenon. We hope that together we can cope with this threat.
Dear readers! Have you ever encountered suspicious behavior of npm-packages?