Published
Updated
Comments0

event-stream compromise

For context, see dominictarr/event-stream#116 or a media article:

Forensic evidence

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.zip:

event-stream-compromise-evidence
├── event-stream@3.3.6
│   ├── 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
├── flatmap-stream@0.1.1
│   ├── LICENSE.txt
│   ├── README.md
│   ├── index.js
│   ├── index.min.js
│   ├── package.json
│   ├── perf-test.js
│   └── test
│       └── data.js
└── flatmap-stream@0.1.2
    ├── 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 flatmap-stream.

flatmap-stream@0.1.1 contains the malicious code and is the most interesting to look at.

Delayed response

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:

@FallingSnow’s @remy/nodemon GitHub comment on Nov 21 2018

At which point I put out an urgent tweet:

@jaydenseric’s tweet on Nov 21 2018

It got very little attention. The JS community that day was apparently more interested in memes and React hooks shitposts:

@ken_wheeler’s tweet on Nov 21 2018

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:

@jaydenseric’s tweet on Nov 22 2018

npm never replied; they only took down the malicious packages after the story went viral a week later.

The nodemon maintainer first responded 22 hours after the threat was detected:

@jaydenseric’s @remy/nodemon GitHub comment on Nov 22 2018

A nodemon version without compromised dependencies was publish relatively soon after. nodemon had a head start; the majority of the JavaScript community continued blissfully unaware for a week before the story went viral.

Reflections

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.

Erased history

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.