npm is the default package manager for Node.js, which is a runtime environment for developing server-side web applications. There are several factors in the npm system that could allow for a worm to compromise the majority of the npm ecosystem: npm encourages the use of semver, or semantic versioning. With semver, dependencies are not locked to a certain version by default. For any dependency of a package, the dependency author can push a new version of the package. npm utilizes persistent authentication to the npm server. Once a user is logged in to npm, they are not logged out until they manually do so. Any user who is currently logged in and types npm install may allow any module to execute arbitrary publish commands. npm utilizes a centralized registry, which is utilized by the majority of the Node.js ecosystem. Typing npm publish ships your code to this registry server, where it can be installed by anyone.

When these three aspects of npm are combined, it provides the capability for a self-replicating worm. The following steps are an example worm workflow outlined in the report provided by Sam Saccone:

Socially engineer a npm module owner to npm install an infected module on their system. Worm creates a new npm module Worm sets a lifecycle hook on the new npm module to execute the worm on any install Worm publishes the new module to the user's npm account Worm walks all of the user’s owned npm modules (with publish permissions) and adds the new module as a dependency in each's package.json . Worm publishes new versions to each of the owned modules with a “bugfix” level semver bump. This ensures the majority of dependent modules using the ^ or ~ signifier will include the self­replicating module during the next install.

The full report from Sam Saccone is available here in PDF form: npmwormdisclosure.pdf



The timeline provided in the above document is as follows:



Jan 1 2016 ­­ Initial discovery of exploit

Jan 4 2016 ­­ Initial disclosure + proof of concept to npm

Jan 5 2016 ­ ­ Private disclosure to Facebook

Jan 7 2016 ­­ Response from npm

Jan 8 2016 ­­ Confirmation of works as intended no intention to fix at the moment from npm.

Feb 5 2016 ­­ Shared the disclosure doc