search menu icon-carat-right cmu-wordmark

CERT Coordination Center


npm fails to restrict the actions of malicious npm packages

Vulnerability Note VU#319816

Original Release Date: 2016-03-26 | Last Revised: 2016-03-26

Overview

npm allows packages to take actions that could result in a malicious npm package author to create a worm that spreads across the majority of the npm ecosystem.

Description

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:

    1. 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.
    2. 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.
    3. 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:
      1. Socially engineer a npm module owner to npm install an infected module on their system.
      2. Worm creates a new npm module
      3. Worm sets a lifecycle hook on the new npm module to execute the worm on any install
      4. Worm publishes the new module to the user's npm account
      5. 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.
      6. 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.pdfnpmwormdisclosure.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

      Impact

      An attacker may be able to create a self-replicating worm that spreads as users install packages.

      Solution

      The CERT/CC is currently unaware of a practical solution to this problem. Please see the npm Blog for details and also consider the following workarounds:

        • As a user who owns modules you should not stay logged into npm. (Easily enough, npm logout and npmlogin)
        • Use npm shrinkwrap to lock down your dependencies
        • Use npminstall someModule --ignore-scripts

      Vendor Information

      319816
      Expand all

      npm

      Notified:  February 12, 2016 Updated:  March 25, 2016

      Status

        Affected

      Vendor Statement

      The lifecycle script feature that the worm relies upon is intrinsic to the
      operation of npm and many other package managers. We have made a decision
      balancing security against utility and decided not to disable this feature.
      Any step short of disabling this feature becomes a cat-and-mouse game of
      attempting to predict what a given user script will do, which becomes akin
      to the halting problem.

      Our real-world mitigation steps are:
      1. registry publishing has a kill switch independent of registry installs,
      so a worm's progress can be instantly halted once identified
      2. we can programmatically identify and un-publish, post-hoc, any
      compromised packages, reverting them to their last good versions

      Users who are uncomfortable with this decision can disable this feature at
      the client side with the `ignore-scripts` option, which can be invoked at
      install time or permanently set with `npm config set ignore-scripts true`.

      Vendor Information

      We are not aware of further vendor information regarding this vulnerability.

      Addendum

      There are no additional comments at this time.

      If you have feedback, comments, or additional information about this vulnerability, please send us email.


      CVSS Metrics

      Group Score Vector
      Base 6.0 AV:N/AC:M/Au:S/C:P/I:P/A:P
      Temporal 5.1 E:POC/RL:W/RC:C
      Environmental 3.8 CDP:ND/TD:M/CR:ND/IR:ND/AR:ND

      References

      Credit

      Thanks to David Ross and Sam Saccone for reporting this vulnerability.

      This document was written by Will Dormann.

      Other Information

      CVE IDs: None
      Date Public: 2016-03-25
      Date First Published: 2016-03-26
      Date Last Updated: 2016-03-26 21:46 UTC
      Document Revision: 44

      Sponsored by the Department of Homeland Security Office of Cybersecurity and Communications.