The Risks of NPM
There was a time when I could ask, “Did you see the latest NPM attack?” And your answer would be either “Yes” or “No”.
But now if I ask, “Did you see the latest NPM attack?” You’ll probably answer with a question of your own: “Which one?”
In this post, I’m talking about the Qix incident:
- Prolific maintainer Qix was phished.
- Qix is a co-maintainer on many packages with Sindre Sorhus, the most popular maintainer on NPM (by download count).
- Attackers pushed malicious code to packages that are indirectly depended by a huge portion of the ecosystem (hundreds of millions of downloads a week).
When I first heard about it, I thought “Oh boy, better not npm i
on the old personal machine for a little while.”
But as details began to emerge, I realized the exploit wasn’t targeting my computer. It was targeting the computers of people downstream from me: end users.
The malicious code didn’t do anything when running npm install
. Instead, it laid there dormant, waiting to be bundled up alongside a website’s otherwise normal code and served to unsuspecting end users.
Maybe we should rename “bundlers” to “trojan horses”, lol.
That’s all to say: you didn’t have to run npm install
to be affected by this attack. You just had to visit a website whose code was sourced via npm install
. (You needed a bitcoin wallet too, as that was the target of the exploit.)
It’s wild because browsers work really hard to make it safe to visit any webpage in the world — to do a GET to any URL. But attacks like this chip away at those efforts.
So while it’s easy to think NPM can be unsafe for your computer because running npm install
allows running arbitrary code, that’s not the whole story. npm install
can be unsafe for:
- Your computer (install time execution)
- Lifecycle scripts (
preinstall
,install
,postinstall
) allow running arbitrary code which can read/write files locally, steal keys and tokens, install malware, and otherwise exfiltrate data.
- Lifecycle scripts (
- Your dev/CI computer(s) (build time execution)
- Compilers, bundlers, transpilers, plugins, etc., can all execute arbitrary code and leak secrets, corrupt build artifacts, add hidden payloads, etc.
- Your application server (server runtime execution)
- Any dependency runs top-level in production and exposes risk to data exfiltration, unsafe privilege escalation, remote command execution, etc.
- Your users’ computers (client runtime execution)
- Bundled dependencies ship with your website, exposing your users to malicious code that runs in their browser and can exfiltrate data, insert hidden trackers/miners, etc.