npm install actual-malware
Tags: security, npm, javascript
Published: 2022-03-14 22:14:08

Need all of your system credentials uploaded to public webpage for easy access? No problem, just run

```sh
npm install actual-malware
```

and you're done! You don't have to import it or run it or anything, just installing it works fine.

(Demo video [here](https://user-images.githubusercontent.com/10591373/158268884-b7a2af72-f59c-419f-b114-e9ad19c471e3.mp4).)

## Why?

NPM recently removed the ability for users to report compromised packages. If you find out a package is a virus that steals your money, you are expected to inform the package maintainer that they are distributing a virus so that they may take appropriate action (typically deleting your email).

Popular npm packages have thousands of dependencies. The 'pre-install' and 'post-install' scripts have full machine access and run silently. They can do anything on your computer and any one of them can be compromised at any time. Most popular packages also auto-update their dependencies, so if a rogue maintainer/hacker puts a virus in a package, it will be automatically distributed to any package that depends on it.

I'm hoping the community sees demonstrations like this and

### What exactly can a post-install script do?

-   **Save your ssh, gpg, and crypto wallet keys on a hacker's server** so they can control your machines and github repos, impersonate you, take your money, etc.
-   **Update your packages to include the virus**. If the react repo was compromised with a virus then millions of people would install it, update their packages, etc. Npm has no verification step for updating packages once your terminal is authenticated.
-   Install a silent daemon that puts a backdoor in your https connection
-   Inject themselves into any ISO or IMG you download on your computer
-   Etc etc

### Is brew, apt, pip, anaconda, yum, git, etc affected?

**YES**

-   [pip](https://stackoverflow.com/questions/20288711/post-install-script-with-python-setuptools)
-   brew packages have full system access
-   same for yum, etc.
-   **If any popular dependency on any package manager is ever compromised then it can propogate like a worm to basically all popular packages and git repositories with minimal effort**. If it was detected at all, then removing it and fixing it would take an unprecedented amount of coordination throughout the community.

(Git is actually the only who did things right here. Git hooks don't come with the repo when you clone it. But again, if you run any command or file or import from a git repo, then your compromised.)

### Can I just disable post-install hooks? What about docker?

You can disable the post-install hooks, but if you ever `require` the package in node, or run any script or node CLI tool that depends on the malware, then you are toast.

Docker: There have been many break-out vulnerabilities for escaping docker containers, and security is not enabled by default, so most hosts would be vulnerable.

### Can't this be detected?

-   Not really.
-   The upload-ssh-keys.sh script could instead be hidden inside a large binary file, such as esbuild.
-   Or it could be put into the minified js after build.
-   Or it could be inside a file called `word2vec-weights.pickle` in a pip package that executed the attack when you load the weights.
-   Etc etc

"What about watching outbound network traffic?" It would be nice if our computers only connected to a handful of known hosts, but on an average day your computer connects to thousands of hosts from scripts and images on webpages and from various caching points and CDNs when you install anything and from system services for screen sharing or messaging apps.

Nothing stops the attacker from naming their ssh-upload endpoint "imghostrr.com/puppy.png"

### What the hell can we do?

All of our package registries are basically screwed. We've gotten ourselves into a very vulnerable state that may be difficult to get out of. But here are some measures that could help a bit:

-   **Allow users once again to report malware on npm, pip, and brew.**
    -   Prevent `npm update` from installing updates with reported malware. (Likewise for pip, brew, apt, etc)
-   **Always require re-authentication for any package upgrade**
    -   It wouldn't hurt if github could also
-   **Prompt users before executing any hooks**
-   **Audit popular packages regularly and have a separate registry with only known, trusted software.**
-   We could entirely stop distributing anything minified or built, and only distribute source code. Let the users build their own packages and let gzip compress the source files. It is actually achievable and builds are quite fast for C at least. The main issue is proprietary software.
    -   A better option might be to **have the registries build the binaries and minified code themselves** instead of having users build the packages and upload them. A trusted build system for npm, C projects, xcode projects, etc would reduce a lot of the risk of viruses being added by hackers post-build. (Trivial attack with minified JS and not too hard with binaries either.)

### What can I do to protect just myself?

-   Put passphrases on all your private keys. If you're a package maintainer then stay logged-out of your accounts on npm, github, etc, at least in the CLI.
-   Use deno instead of node to run scripts. (Sorry python users.)
-   Disable pre-install and post-install hooks in npm. (Sorry python users.)
-   For python and node, something like [firejail](https://github.com/netblue30/firejail) can limit the reach of scripts and libraries.
    -   It's not too much trouble once you get the workflow down.
-   Docker with root protection enabled is decent. Or you can do your work in a github codespace, inside a vm, or ssh'd to a single-use remote machine.

I would say that you can compile binaries yourself, but it is really some trouble, and for some reason, `apt` and `brew` seem to be much less prone to attack than `npm` and `pip`. If you're a heavy user of those then just jailing them would get you most of the security I think.

Anyway the community really should do something here, instead of just letting this lie like it has for the last decade...