For context, see dominictarr/event-stream#116 or a media article:
- Ars Technica – “Widely used open source software contained bitcoin-stealing backdoor”
- The Register – “Check your repos... Crypto-coin-stealing code sneaks into fairly popular NPM lib (2m downloads per week)”
As the compromised and malicious releases have been unpublished from the npm registry and purged from most mirrors and CDNs, for security research purposes you may download the archive
event-stream-compromise-evidence ├── firstname.lastname@example.org │ ├── LICENCE │ ├── examples │ │ ├── data │ │ ├── map.js │ │ ├── pretty.js │ │ └── split.js │ ├── index.js │ ├── package.json │ ├── readme.markdown │ └── test │ ├── connect.asynct.js │ ├── flatmap.asynct.js │ ├── helper │ │ └── index.js │ ├── merge.asynct.js │ ├── parse.asynct.js │ ├── pause.asynct.js │ ├── pipeline.asynct.js │ ├── readArray.asynct.js │ ├── readable.asynct.js │ ├── replace.asynct.js │ ├── simple-map.asynct.js │ ├── spec.asynct.js │ ├── split.asynct.js │ ├── stringify.js │ └── writeArray.asynct.js ├── email@example.com │ ├── LICENSE.txt │ ├── README.md │ ├── index.js │ ├── index.min.js │ ├── package.json │ ├── perf-test.js │ └── test │ └── data.js └── firstname.lastname@example.org ├── LICENSE.txt ├── README.md ├── index.js ├── index.min.js ├── package.json ├── perf-test.js └── test └── data.js
Chances are you can source these unpublished package versions yourself by Finder searching the
node_modules of a project npm installed in last month or so (but not yet updated) for
email@example.com contains the malicious code and is the most interesting to look at.
I first caught wind something was fishy a month ago (October 29, 2018), when I could't work out why
nodemon was emitting a crypto deprecation warning in Node.js v11 (remy/nodemon#1442):
[DEP0106] DeprecationWarning: crypto.createDecipher is deprecated.
It was not until November 21, 2018 that Ayrton Sparling figured out it was due to an attack:
At which point I put out an urgent tweet:
It got very little attention. The JS community that day was apparently more interested in memes and React hooks shitposts:
It took far too long for the community to mobilize.
I attempted to report the threat to npm the next day, as the
event-stream maintainer didn't seem so inclined (a reliable instinct). At first it was not obvious the right way to go about it; I filed a report at npmjs.com/advisories/report, but after submitting it redirected to a 404 page, I got no confirmation email or anything, and there appeared to be no place to track the status. So I tweeted npm to make sure they got it:
npm never replied; they only took down the malicious packages after the story went viral a week later.
nodemon maintainer first responded 22 hours after the threat was detected:
nodemon version without compromised dependencies was publish relatively soon after.
Code on GitHub & npm can differ
It is problematic that package source code on Github, what most people scrutinize, can be totally different to what is published to npm. Hackers are exploiting this to undermine the open source “many eyes” security advantage.
For packages with a repository field, the
npm publish command could accept a commit hash argument and the actual packaging could take place on npm servers, pulling the relevant commit. This will have the nice side-effect of ensuring packages can be built reliably from dev dependencies and scripts in environments other than the original author’s.
Security report gatekeeping
- The reporting form could be more obvious and better tested.
- Reports via alternative channels such as Twitter should not be ignored.
- There is always a delay between the initial community report and an official advisory or response, if there is one.
It would be nice if there was a way to audit your projects for unconfirmed community reports of active security threats. There needs to be a clear distinction in the reporting process between security vulnerabilities, which should not be immediately disclosed to the public, and active threats, which should.
Instead of removing bad versions of compromised or malicious packages from the npm registry as if they never existed, they should be made only installable with a special flag. This would reduce confusion and allow security researchers to do their thing without having to contact each other asking for copies.