npm / npm/rfcs

[RRFC] Approved package lists

Open
#480 4 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
777
Forks
267
PR merge metrics
No merged PRs in 30d

Description

Motivation ("The Why")

Today (10/22/21), ua-parser-js was maliciously compromised, a package with millions of downloads per week. The npm team responded quickly, but there was a 4-hour window where many people could have been affected. This includes those with with a package-lock.json if they were modifying dependencies. This RRFC aims to put an end to compromised transitive dependencies.

"The How"

I propose that npm implements a new feature called "Approved package lists" (name of course up for discussion). This would be an entirely opt-in feature for teams where security is critical. Here's how it works:

  • The npm package manager is now aware of a new special file, package-approvals.json. This would live along side package.json and package-lock.json. It would be excluded from files published to the registry on npm publish.
  • This file would have the following structure (for the initial version):
{
    version: number,
    packages: {
        [<package-name>]: string[],
    },
    extends?: string; // file path or URL
}

In each array associated with the package, there would be a string of version numbers, e.g. ['1.0.0', '1.1.9', '2.3.4']. Importantly, there would be no support for ranges of versions.

  • A number of commands would be added to the npm cli, such as npm approve <package-name>@<version>, npm unapprove <package-name>@<version>, and npm approve --all-current-packages. The npm approve --all-current-packages would have a Yes/No prompt to confirm this choice.
  • The package.json file would support a new key: approvals?: string. This optional key could either be a relative/absolute path to a file with the package-approvals.json structure or a URL to retrieve the file.

The idea behind the above proposal would be to change how npm install/npm ci works, and would apply to workspaces. On install, if npm would resolve a package (including transitive packages) but the package version does not exist in the approvals list, npm would error. Importantly, this would occur before any files are written to disk and package scripts (e.g. postinstall) are run. The error could include a list of all packages that don't satisfy the approvals. Developers could resolve this error by running npm approve <package-name>@<version> for a single one, or (if they are really sure their current dependencies are safe), run npm approve --all-current-packages. These convenience scripts would modify the local package-approvals.json file.

Developers would be able to leverage this new file by guaranteeing that they never use an un-audited dependency. Each team of developers could perform their own audit of the dependencies they wish to use, then add each one to the approvals list. This could be a time consuming task, but worth it. To alleviate some of the burden, this file could be hosted somewhere accessible by the internet, so teams or individuals could share their configuration via the approvals package.json field. Additionally, the package-approvals.json has an extends field that could resolve and recursively extend other package-approvals.json files. Obviously there are too many npm packages to have a single community-hosted package-approvals.json file for everyone, but the community could create shared ones for different use-cases.

Example
{
    version: 1,
    extends: 'https://example.com/path/to/some/package-approvals.json',
    packages: {
        lodash: ['4.17.19', '4.17.21'],
        react: ['16.0.8', '17.0.2'],
        // and many more
    },
}

I feel that something like this would greatly improve security in the npm community. Please let me know what you think, or if there is a similar RRFC like this already.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the proposed package-approvals.json structure alongside package.json and package-lock.json, then trace the npm install and npm ci entry points and the proposed approve/unapprove commands. Done means the opt-in approval list, workspace behavior, pre-install rejection, and approval commands are specified and covered by appropriate tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
cli, security, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.