├── draft └── .gitkeep ├── published ├── .gitkeep └── npm.md ├── review └── .gitkeep ├── README.md ├── .github └── settings.yml ├── process.md └── LICENSE /draft/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /published/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /review/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Package Manager Best Practices** 2 | 3 | Collection of security best practices documentation for various package 4 | managers 5 | 6 | A project under the [Best Practices for Open Source Developers 7 | WG](https://github.com/ossf/wg-best-practices-os-developers). 8 | 9 | ## **Motivation** / **Objective** 10 | 11 | This project intends to create documents that cover the recommend way to use 12 | various package managers for optimum security. 13 | 14 | [Video introduction starts here](https://youtu.be/b7p8U6H2jcI?t=2396) 15 | 16 | ## **Scope** 17 | 18 | Documents for package managers, such as: 19 | 20 | * npm 21 | * Pip 22 | * RubyGems 23 | * etc. 24 | 25 | ## **Process** 26 | 27 | The procedure for proposing, reviewing, and publishing guideline documents is covered in [process.md](process.md) 28 | 29 | # **Get Involved** 30 | 31 | * See [Best Practices for Open Source Developers WG](https://github.com/ossf/wg-best-practices-os-developers) for meetings/lists/slack/etc. 32 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | repository: 2 | # See https://developer.github.com/v3/repos/#edit for all available settings. 3 | 4 | # The name of the repository. Changing this will rename the repository 5 | name: project-template 6 | 7 | # A short description of the repository that will show up on GitHub 8 | description: OpenSSF Project Template 9 | 10 | # A URL with more information about the repository 11 | homepage: https://openssf.org 12 | 13 | # Collaborators: give specific users access to this repository. 14 | # see /governance/roles.md for details on write access policy 15 | # note that the permissions below may provide wider access than needed for 16 | # a specific role, and we trust these individuals to act according to their 17 | # role. If there are questions, please contact one of the chairs. 18 | collaborators: 19 | # Chairs and Admin Help 20 | - username: 21 | permission: admin 22 | 23 | # Contributors 24 | # all permissions except admin 25 | 26 | - username: 27 | permission: push 28 | 29 | labels: 30 | - name: helpwanted 31 | color: ffff54 32 | - name: good first issue 33 | color: ff8c00 34 | - name: meeting 35 | color: 00ff00 36 | 37 | # additional colors in this palette: 38 | # 7f0000 , 1e90ff, ffdab9, ff69b4 39 | -------------------------------------------------------------------------------- /process.md: -------------------------------------------------------------------------------- 1 | # **Process for introducing new guide documents** 2 | 3 | 1. First, a draft is developed outside this repository among authors. To avoid 4 | duplication of effort, authors may open an issue. The title should start 5 | with "In progress:". 6 | 7 | 1. Towards the end of the draft phase, at the point the authors wish to engage 8 | wider collaboration, the authors may open a PR with the draft document 9 | against the `draft/` directory. This PR will be merged by repository 10 | maintainers without review. At this time the above "In progress:" issue 11 | should be closed. 12 | 13 | 1. The document may live in `draft/` for as long as the authors 14 | wish. Repository maintainers will merge any PRs from authors on these drafts 15 | without review. 16 | 17 | 1. When the authors are ready to submit the draft for formal review, they open 18 | a PR to move the draft to the `review/` directory. At this point an RFC 19 | announcement is made to the Working Group. This starts a 30-day count 20 | down. An issue is created (Title: "RFC for Foo guide closes yyyy-mm-dd") 21 | under a new Milestone with the due-date 30 days away. 22 | 23 | 1. During the review time, comments are taken in the form of issues. The title 24 | should start with "RC Foo:", where Foo is the name of the guide. 25 | 26 | 1. Authors address review comments by making PRs to the guide and closing out 27 | the comments. 28 | 29 | 1. After the 30 day period is over, the guide will be moved from the `review/` 30 | to the `published/` directory once all issues are resolved. The guide will 31 | be given the version 1.0 32 | 33 | ## **Process for maintaining published guides** 34 | 35 | * Repository maintainers will regularly triage incoming issues on published 36 | guides with the tags: 37 | 38 | * Minor: The fix is obvious or clear. Does not need in-depth review and RFC 39 | period. (e.g., typo) 40 | 41 | * Major: Improvements to guide that require more in-depth expertise. 42 | 43 | * Critical: Problems that cause security issues when following guide as is. 44 | 45 | * At least every 3 months, repository maintainers will address all minor issues 46 | on guides, then bump the minor version. 47 | 48 | * Major issues will be postponed until available authors can take on a major 49 | version update. This will follow the same workflow as new guides above. 50 | 51 | * Critical issues will be floated up to WG discussion, and a call for help made 52 | there. 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /published/npm.md: -------------------------------------------------------------------------------- 1 | # npm Best Practices Guide 2 | 3 | Version 1.1 4 | 5 | This document aims to be an all-inclusive document explaining the security supply-chain 6 | best practices when using npm's package manager. It is one of the workstreams 7 | of the OSSF's [Best Practices for Open Source 8 | Developers](https://github.com/ossf/wg-best-practices-os-developers) working 9 | group. This document provides 10 | 11 | 1. an overview of the security features of npm in the context of supply-chain 12 | 2. explicit recommendations 13 | 3. details or links to the official documentation to achieve these recommendations. This document is 14 | intended to complement the official npm documentation, not to be an alternative. 15 | 16 | ## Table of Contents 17 | 18 | - [npm Best Practices Guide](#npm-best-practices-guide) 19 | - [Table of Contents](#table-of-contents) 20 | - [CI configuration](#ci-configuration) 21 | - [Dependency management](#dependency-management) 22 | - [Intake](#intake) 23 | - [Declaration](#declaration) 24 | - [Project types](#project-types) 25 | - [Reproducible installation](#reproducible-installation) 26 | - [Vendoring dependencies](#vendoring-dependencies) 27 | - [Use a Lockfile](#use-a-lockfile) 28 | - [package-lock.json](#package-lockjson) 29 | - [npm-shrinkwrap.json](#npm-shrinkwrapjson) 30 | - [Lockfiles and commands](#lockfiles-and-commands) 31 | - [Maintenance](#maintenance) 32 | - [Vulnerability Disclosure](#vulnerability-disclosure) 33 | - [Release](#release) 34 | - [Account](#account) 35 | - [Signing and Verification](#signing-and-verification) 36 | - [Publishing](#publishing) 37 | - [Private packages](#private-packages) 38 | - [Scopes](#scopes) 39 | - [Private registry configurations](#private-registry-configurations) 40 | 41 | ## CI configuration 42 | 43 | Follow the [principle of least privilege](https://www.cisa.gov/uscert/bsi/articles/knowledge/principles/least-privilege) 44 | for your CI configuration. 45 | 46 | If you run CI via GitHub Actions, a non-privileged environment is a workflow **without** access to 47 | GitHub secrets and with non-write permissions defined, such as `permissions: read-all`, `permissions:`, 48 | `contents: none`, `contents: read`. For more information about permissions, refer to the [official documentation](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token). 49 | 50 | You may install the [OpenSSF Scorecard Action](https://github.com/ossf/scorecard-action) 51 | to flag non-read permissions on your project. 52 | 53 | ## Dependency management 54 | 55 | ### Intake 56 | 57 | The first step to using a dependency is to study its origin, trustworthiness 58 | and security posture. Projects like [Envoy 59 | proxy](https://github.com/envoyproxy/envoy) have [well-documented 60 | criteria](https://github.com/envoyproxy/envoy/blob/main/DEPENDENCY_POLICY.md#new-external-dependencies) 61 | a dependency must meet before it is used. 62 | 63 | **Recommendations:** 64 | 65 | 1. **Be aware of typosquatting attacks**, when an attacker creates an 66 | official-looking package name to trick users into installing rogue packages 67 | ([1](https://threatpost.com/discord-stealing-malware-npm-packages/163265/), 68 | [2](https://blog.sonatype.com/damaging-linux-mac-malware-bundled-within-browserify-npm-brandjack-attempt), 69 | [3](https://blog.npmjs.org/post/163723642530/crossenv-malware-on-the-npm-registry)). Although 70 | the npm registry performs scans to detect typosquatting; no system is 71 | perfect, so stay vigilant. Identify the GitHub repository of the package and 72 | assess its trustworthiness through, for example, its number of contributors, 73 | stars, etc. 74 | 75 | 1. Additionally, uppercase characters were previously allowed, which is another 76 | attack vector to be aware of. For example: [JSONStream](https://www.npmjs.com/package/JSONStream), 77 | [jsonstream](https://www.npmjs.com/package/jsonstream). 78 | 79 | 2. Note: Non-ASCII characters are [no longer supported in the npm package 80 | names](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#name), 81 | so developers need not worry about homograph attacks from the public registry, whereby an attacker 82 | names their package using non-ASCII characters that render similar to an 83 | ASCII character. Note that this property is registry-dependent; 84 | you will need to verify this policy with any registry you use. 85 | 86 | 2. When you determine a GitHub project of interest, follow their documentation 87 | to identify the corresponding package name. 88 | 89 | Use [OpenSSF Security Scorecards](http://github.com/ossf/scorecard) to 90 | learn about the current security posture of the dependency. 91 | 92 | 3. Use [deps.dev](http://deps.dev) to learn about the security posture of 93 | transitive dependencies. You may list transitive dependencies by using 94 | [component analysis](https://github.com/microsoft/component-detection/). 95 | 96 | 4. Use [npm-audit](https://docs.npmjs.com/cli/v8/commands/npm-audit) to learn 97 | about existing vulnerabilities in the dependencies of the project. 98 | 99 | **Warning**: Organization verification does not exist on the npm registry, and 100 | it's "first-come, first serve." It is possible to challenge the owner of an org 101 | for squatting after the fact using the [dispute 102 | process](https://docs.npmjs.com/policies/disputes#beginning-the-process). 103 | 104 | ### Declaration 105 | 106 | In npm, the 107 | [package.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-json) 108 | describes a project (name, components, dependencies, etc.). Dependencies may be 109 | defined by a package name, URL, repo, etc. Additional constraints may be 110 | defined for each dependency, such as which tags, branches, versions, or 111 | commit-ish are allowed. 112 | 113 | **Note**: The manifest file ***does not*** list transitive dependencies; it 114 | only lists direct project dependencies. 115 | 116 | ### Project types 117 | 118 | In the rest of this document, we will refer to three types of projects: 119 | 120 | - **Libraries**: These are projects published on the npm registry and consumed 121 | by other projects in the form of API calls. (Their manifest file 122 | typically contains a `main`, `exports`, `browser`, `module`, and/or `types` entry). 123 | 124 | - **Standalone CLIs**: These are projects published on the npm registry 125 | and consumed by end-users in the form of locally installed programs that 126 | are **always** run stand-alone via `npx` or via a global install. 127 | An example would be [clipboard-cli](https://github.com/sindresorhus/clipboard-cli). 128 | (Their manifest file contains a `bin` entry). 129 | 130 | - **Application projects**: These are projects that teams collaborate on in 131 | development and deployment, such as websites and/or web applications. 132 | An example would be a React web app for a company's user-facing SaaS. 133 | (Their manifest file typically contains `"private": true`). 134 | 135 | ### Reproducible installation 136 | 137 | A reproducible installation guarantees an exact, identical copy the 138 | dependencies are used each time the package is installed. This has various 139 | benefits, including: 140 | 141 | - Ensuring the dependencies installed are the ones declared and reviewed via 142 | pull requests. 143 | 144 | - Helping quickly indentify possible compromises of your infrastructure if one 145 | of your dependencies is found to have vulnerabilities, as you will be able to 146 | promptly determine the commit range of when your repository is at risk. 147 | 148 | - Mitigating certain threats such as malicious dependencies. Otherwise, you might 149 | install and run a newly published (compromised) version of the dependency on 150 | a CI/CD system or developer machine, giving an attacker immediate code execution. 151 | 152 | - Detecting package corruptions before installation, for example, due to RAM 153 | corruption. 154 | 155 | - Mitigating package mutability introduced by misconfigured registries that 156 | proxy packages from public registries. Note: Versions are immutable in 157 | principle, but the registry enforces immutability. 158 | 159 | - Improve the accuracy of automated tools such as GitHub's security alerts. 160 | 161 | - Let maintainers test updates before accepting them in the default branch, 162 | e.g., via renovatebot's [stabilityDays](https://docs.renovatebot.com/configuration-options/#stabilitydays). 163 | 164 | There are two ways to achieve a reproducible installation reliably: vendoring 165 | dependencies and pinning by hash. 166 | 167 | #### Use a Lockfile 168 | 169 | Use a lockfile because it implements hash pinning using cryptographic hashes. 170 | Hash pinning informs the package manager of the expected hash for each dependency 171 | without trusting the registries. During each installation, the package manager then 172 | verifies that the hash of each dependency remains the same. Any malicious 173 | change to the dependency would be detected and rejected. 174 | 175 | Npm provides two options to achieve hash pinning. 176 | 177 | ##### package-lock.json 178 | 179 | The 180 | [package-lock.json](https://docs.npmjs.com/cli/v6/configuring-npm/package-lock-json) 181 | contains ***all*** the dependencies (direct and indirect) along with a 182 | cryptographic hash of their content: 183 | 184 | ```json 185 | { 186 | "name": "A", 187 | "version": "0.1.0", 188 | ...metadata fields... 189 | "dependencies": { 190 | "B": { 191 | "version": "0.0.1", 192 | "resolved": "https://registry.npmjs.org/B/-/B-0.0.1.tgz", 193 | "integrity": "sha512-DeAdb33F+" 194 | "dependencies": { 195 | "C": { 196 | "version": "git://github.com/org/C.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4" 197 | } 198 | } 199 | } 200 | } 201 | } 202 | ``` 203 | 204 | The `package-lock.json` file is a ***snapshot of an installation*** that allows 205 | later reproduction of the same installation. As such, the lock file is 206 | generated or updated via the various commands that install packages, e.g., `npm install`. If some dependencies are missing or not pinned by hash (e.g., 207 | the `integrity` field is not present), the installation will patch the lock file to 208 | reflect the installation. 209 | 210 | The lock file ***cannot*** be uploaded to a registry, which means that 211 | consumers who locally install the package via `npm install` may [see different 212 | dependency 213 | versions](https://dev.to/saurabhdaware/but-what-the-hell-is-package-lock-json-b04) 214 | than the repo owners used during testing. Using `package-lock.json` is akin to 215 | dynamic linking for low-level programming languages: the loader will resolve 216 | dependencies at load time using libraries available on the system. Using this 217 | lock file leaves the task of deciding dependencies' versions to use to the 218 | package consumer. 219 | 220 | ##### npm-shrinkwrap.json 221 | 222 | [npm-shrinkwrap.json](https://docs.npmjs.com/cli/v7/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson) 223 | is another lock file supported by npm. The main difference is that this lock 224 | file ***may*** be uploaded to a registry along with the package. This ensures that 225 | consumers obtain the same dependencies' hashes as the 226 | repo owners intended. With `npm-shrinkwrap.json`, the package producer takes 227 | responsibility for updating the dependencies on behalf of their consumers. It's 228 | akin to static linking for low-level programming languages: everything is 229 | declared at packaging time. 230 | 231 | To generate the `npm-shrinkwrap.json`, an existing `package-lock.json` must be present, 232 | and the command [`npm shrinkwrap`](https://docs.npmjs.com/cli/v8/commands/npm-shrinkwrap) must be 233 | run. 234 | 235 | #### Lockfiles and commands 236 | 237 | Certain `npm` commands treat the lockfiles as read-only, while others do not. 238 | 239 | The following commands treat the lock file as read-only: 240 | 241 | 1. [`npm ci`](https://docs.npmjs.com/cli/v8/commands/npm-ci), used to 242 | install a project and its dependencies, 243 | 244 | 2. [`npm install-ci-test`](https://docs.npmjs.com/cli/v8/commands/npm-install-ci-test), 245 | used to install a project and run tests. 246 | 247 | The following commands ***do not*** treat the lock file as read-only, may fetch / install 248 | unpinned dependencies and update the lockfiles: 249 | 250 | 1. `npm install`, `npm i`, `npm install -g` 251 | 252 | 2. `npm update` 253 | 254 | 3. `npm install-test` 255 | 256 | 4. `npm pkg set` and `npm pkg delete` 257 | 258 | 5. `npm exec`, `npx` 259 | 260 | 6. `npm set-script` 261 | 262 | **Recommendations:** 263 | 264 | 1. Developers should declare and commit a manifest file for ***all*** their 265 | projects. To create the manifest file, use the official [Creating a package.json 266 | file](https://docs.npmjs.com/creating-a-package-json-file) documentation. 267 | 268 | 2. To add a dependency to a manifest file, ***locally*** run [`npm install --save `](https://docs.npmjs.com/cli/v8/commands/npm-install) 269 | and commit the updated manifest to the repository. 270 | 271 | 3. If you need to run a standalone CLI package from the registry, ensure the package is a part of 272 | the dependencies defined in your project via the `package.json` file, before 273 | being installed at build-time in your CI or otherwise automated environment. 274 | 275 | 4. Developers should declare and commit a lockfile for ***all*** their 276 | projects. The reasoning is that this lockfile will provide the benefits of 277 | [Reproducible installation](#reproducible-installation) 278 | by default for privileged environments (project developers' machines, 279 | CI, production or other environments with access to sensitive data, 280 | such as secrets, PII, write/push permission to the repository, etc). 281 | 282 | When running tests locally, developers should use commands that treat a lockfile 283 | as read-only (see [Lockfiles and commands](#lockfiles-and-commands)), unless they 284 | are intentionally adding/removing a dependency. 285 | 286 | Below we explain the lockfile acceptable by project type. 287 | 288 | 5. If a project is a library: 289 | 290 | 1. An `npm-shrinkwrap.json` ***should not*** be published. 291 | The reasoning is that version resolution should be left to the package consumer. 292 | Allow all versions from the minimum to the latest you support, e.g., 293 | `^m.n.o` to pin to a major range; `~m.n.o` to pin to a minor range. Avoid versions 294 | with critical vulnerabilities as much as possible. Visit the [semver 295 | calculator](https://semver.npmjs.com/) to help define the ranges. 296 | 297 | 2. The lockfile `package-lock.json` ***should*** be ignored for tests running in CI 298 | (e.g. via `npm install --no-package-lock`). The reasoning is that CI tests should 299 | exercise a wide range of dependency versions to discover/fix problems 300 | before the library users do, so tests need to pull the latest versions of packages. 301 | 302 | 3. Locally, developers should only run npm commands that treat the lockfile as 303 | read-only (see [Lockfiles and commands](#lockfiles-and-commands)), except 304 | when intentionally adding /removing a dependency. 305 | 306 | 4. Follow the principle of least privilege in your [CI configuration](#ci-configuration). 307 | This is particularly important since the lockfile is ignored. 308 | 309 | 6. If a project is a standalone CLI: 310 | 311 | 1. Developers may publish an `npm-shrinkwrap.json`. 312 | Remember that by declaring an `npm-shrinkwrap.json`, you take responsibility 313 | for rapidly and consistently updating all the dependencies. Your users will not be able 314 | to edit or deduplicate them. If you expect your CLI to be used by other projects and defined 315 | in their `package.json` or lockfile, do **not** use `npm-shrinkwrap.json` because it will 316 | hinder dependency resolution for your consumers: follow the recommendations as if your project 317 | was a library. 318 | 319 | 2. In CI, only run npm commands that treat the lockfile as 320 | read-only (see [Lockfiles and commands](#lockfiles-and-commands)). 321 | 322 | 3. Locally, developers should only run npm commands that treat the lockfile as 323 | read-only (see [Lockfiles and commands](#lockfiles-and-commands)), except 324 | when intentionally adding /removing a dependency. 325 | 326 | 4. Follow the principle of least privilege in your [CI configuration](#ci-configuration). 327 | 328 | 7. If a project is an application: 329 | 330 | 1. Developers should declare and commit a lockfile to their repository. 331 | 332 | 2. In CI, only run npm commands that treat the lockfile as 333 | read-only (see [Lockfiles and commands](#lockfiles-and-commands)). 334 | 335 | 3. Locally, developers should only run npm commands that treat the lockfile as 336 | read-only (see [Lockfiles and commands](#lockfiles-and-commands)), except 337 | when intentionally adding /removing a dependency. 338 | 339 | #### Vendoring dependencies 340 | 341 | Vendoring dependencies denotes keeping a local copy of all the dependencies 342 | (direct and transitive) in the repository. While vendoring can solve the 343 | "reproducible installation" problem, it also can encourage insecure practices. 344 | These include poor ability to audit dependency code, difficulties keeping 345 | dependencies up to date, and more. Also, vendoring introduces non-security problems 346 | like repository size, usability, and developer experience issues. For these 347 | reasons, vendoring is not recommended without tooling and solutions to address 348 | those problems outside this document's scope. 349 | 350 | ### Maintenance 351 | 352 | It is crucial to update dependencies periodically, particularly when new 353 | vulnerabilities are disclosed and patched. Tools that help with dependency 354 | management are easy to use and may implement security checks for you. 355 | 356 | **Recommendations:** 357 | 358 | 1. To manage your dependencies, use a tool such as 359 | [dependabot](https://docs.github.com/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/configuring-dependabot-security-updates) 360 | or [renovatebot](https://github.com/renovatebot/renovate). These tools 361 | submit merge requests that you may review and merge into the default branch. 362 | 363 | 2. Stay up to date about existing vulnerabilities in your dependencies: 364 | 365 | 1. If you have installed the tools above, enable security alerts: see 366 | [dependabot 367 | config](https://docs.github.com/en/code-security/supply-chain-security/managing-vulnerabilities-in-your-projects-dependencies/about-alerts-for-vulnerable-dependencies#dependabot-alerts-for-vulnerable-dependencies) 368 | and [renovatebot 369 | config](https://docs.renovatebot.com/configuration-options/#vulnerabilityalerts). Note 370 | that renovatebot follows config-as-code, so it makes it easier for 371 | external users to verify that it is enabled. 372 | 373 | 2. If you prefer a dedicated tool, run 374 | [npm-audit](https://docs.npmjs.com/cli/v8/commands/npm-audit) 375 | periodically, e.g., in a GitHub workflow. 376 | 377 | 3. To remove dependencies, periodically run [`npm prune`](https://docs.npmjs.com/cli/v8/commands/npm-prune) and submit a merge 378 | request. The tools above do not support this feature yet, and we are not aware 379 | of a GitHub action for this feature. 380 | 381 | ## Vulnerability Disclosure 382 | 383 | Vulnerability disclosure comes in two major halves. Researchers discovering and reporting vulnerabilities to software maintainers and software maintainers further notifying the users of their software to known vulnerabilities. The [OpenSSF](https://openssf.org/) [maintains a set of general recommendations](https://github.com/ossf/oss-vulnerability-guide/) regarding vulnerability disclosure which maintainers should consult for more details. 384 | 385 | ### Researcher to maintainer disclosure 386 | 387 | Software maintainers should make it easy and clear how to privately disclose vulnerabilities. GitHub [recommends creating a security.md file](https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository) with contact information that a researcher can use to privately disclose security vulnerabilities they discover. Maintainers should ensure that some method of private communication is possible for well-intentioned security researchers lest they accept that all disclosure be public. 388 | 389 | ### Maintainer to user disclosure 390 | 391 | Most projects tend to have vulnerabilities discovered in them over their lifetime and it's important that those vulnerabilities get disclosed to users in a clear and concise manner. Disclosing vulnerabilities with a [CVE](https://cve.mitre.org/), [GHSA](https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories), or other indexing number will allow automated systems to discover, ingest, and report to users any relevant vulnerabilities. For these automated systems to work well the source advisory should be as detailed as possible calling out specific npm package names, versions, and code changes which resolve the issue. 392 | 393 | ## Release 394 | 395 | ### Account 396 | 397 | Publishing on the npm registry requires creating a user account. 398 | 399 | **Recommendations:** 400 | 401 | 1. Developers should [enable 402 | 2FA](https://docs.npmjs.com/configuring-two-factor-authentication) on their 403 | account. 404 | 405 | ### Signing and Verification 406 | 407 | npm packages are all signed by a [ECDSA Key]([https://docs.npmjs.com/about-pgp-signatures-for-packages-in-the-public-registry](https://docs.npmjs.com/about-registry-signatures)) 408 | owned by the default npm registry. 409 | 410 | [Signatures can be verified](https://docs.npmjs.com/verifying-registry-signatures) with the npm CLI v8.15.0 or later with the command `npm audit signatures`. 411 | 412 | **Warning**: npm does not support user-level signatures. 413 | 414 | ### Publishing 415 | 416 | Publishing a package uploads it to a registry for others to install and 417 | download. 418 | 419 | **Recommendations:** 420 | 421 | 1. When using a CI system to publish, use an [Automation 422 | token](https://docs.npmjs.com/creating-and-viewing-access-tokens) to 423 | authenticate and publish to the default npm registry. 424 | 425 | 2. Release your package using the commands: 426 | 427 | ```shell 428 | npm ci 429 | npm publish 430 | ``` 431 | 432 | 3. Consumers of public packages may fall victim to typosquatting attempts. To 433 | mitigate this problem, and create and own your organization on other registries. 434 | 435 | **Note**: 436 | 437 | 1. The default npm registry does not support the default GitHub token for 438 | authentication, so users need to save it as a [GitHub 439 | secret](https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry). 440 | 441 | 2. There is no official GitHub action to publish an npm package. 442 | 443 | 3. [CIDR-scoped 444 | tokens](https://docs.npmjs.com/creating-and-viewing-access-tokens#cidr-restricted-token-errors) 445 | are scoped by IP range for additional protection but can only be created 446 | with the npm CLI. 447 | 448 | ## Private packages 449 | 450 | Dependency confusion attacks, a.k.a substitution attacks, occur when a project 451 | relies on private packages from an internal registry. An attacker may register 452 | the same package name on public registries. By default, npm will fetch the 453 | dependency from the public registry—see details of recent attacks in Alex 454 | Birsan's 455 | [blog](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610). To 456 | alter this behavior so npm fetches the correct dependency, use scopes. 457 | 458 | ### Scopes 459 | 460 | A "scope" is a @-prefixed name that goes at the start of a package name. For 461 | example, `@myorg/foo` is a scoped package. Scoped packages are used like any 462 | other packages in package.json and Javascript code: 463 | 464 | ```json 465 | { 466 | "name": "@myorg/foo", 467 | "version": "1.2.3", 468 | "description": "just a scoped package name example", 469 | "dependencies": { 470 | "@myorg/bar": "2.x" 471 | } 472 | } 473 | ``` 474 | 475 | ```js 476 | // es modules style 477 | import foo from "@myorg/foo"; 478 | 479 | // commonjs style 480 | const foo = require("@myorg/foo"); 481 | ``` 482 | 483 | Scoped packages on the public npm registry may only be published by the user or 484 | organization associated with it, and packages within that scope may be made 485 | private. Also, scope names can be linked to a given registry. 486 | 487 | **Recommendations:** 488 | 489 | 1. On the public npm registry, [create a free 490 | organization](https://docs.npmjs.com/creating-an-organization) with the 491 | “myorg” name. At that point, no one else can publish anything under the 492 | `@myorg` scope on the public registry and your builds will fail with `404 errors` if they’re misconfigured, rather than silently fetching untrusted 493 | content. This is crucial because it prevents an attacker from 494 | hijacking your organization’s name in the public registry, which could 495 | result in the same problems. 496 | 497 | 2. Locally, use the login command to ensure that all requests for packages 498 | under the `@myorg` scope will be made to the `https://registry.myorg.local` 499 | registry. Any other requests not bound to a scope will go to the 500 | default registry. 501 | 502 | ```shell 503 | npm login --scope=myorg --registry=https://registry.myorg.local 504 | ``` 505 | 506 | This saves the login information in your `~/.npmrc` file as follows: 507 | 508 | ```js 509 | @myorg:registry = https://registry.myorg.local/ 510 | //registry.myorg.local:_authToken = xyzabc123-arbitrary-token-value 511 | ``` 512 | 513 | 3. Do not commit this file `~/.npmrc` with credentials to a repository. 514 | 515 | 4. In automated environments, provision the secret automatically. Follow a 516 | similar solution as [GitHub uses in 517 | workflows](https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages). If 518 | your registry supports ephemeral credentials, use it instead of using 519 | long-term secrets/tokens. 520 | 521 | 5. Create a `.npmrc` file in the root of your projects, with a line like this 522 | 523 | ```js 524 | @myorg:registry = https://registry.myorg.local/ 525 | ``` 526 | 527 | You can check the currently configured registry at any time by running this command. 528 | 529 | ```shell 530 | npm config get registry 531 | ``` 532 | 533 | By doing this, npm will associate the scope with your internal registry when working on that project. 534 | 535 | For more information on the topic, see [npm's substitution attack blog 536 | post](https://github.blog/2021-02-12-avoiding-npm-substitution-attacks/). 537 | 538 | ### Private registry configurations 539 | 540 | If you use internal private registries: 541 | 542 | 1. Only use private registry solutions that support scopes 543 | 544 | 2. Make your private packages immutable: 545 | 546 | 1. Ensure your registry is not configured to “merge” manifests of the same 547 | name from the upstream public registry. This is sometimes enabled to 548 | work around resolution collisions, but it is a terrible idea, precisely 549 | because “workaround resolution collisions” is how name hijacking 550 | exploits work. If possible, use a private registry implementation that 551 | doesn’t even have this feature. 552 | 553 | 2. Once a package is published to the internal proxy registry, it is very 554 | important that you do not silently fall back to the public registry if 555 | that package is ever removed. If the proxy starts serving this package 556 | name from the public registry, you are back in a situation where an 557 | attacker can take over the name and gain access to any systems that are 558 | left behind. 559 | 560 | 3. Do not ignore build failures. If you configure your projects as above, you 561 | will likely see a 404 error rather than npm fetching untrusted content. Do not 562 | ignore these errors! Configure your systems to crash as loudly as possible if a 563 | build fails, and fix it immediately. 564 | 565 | For more information on the topic, see [npm's substitution attack blog 566 | post](https://github.blog/2021-02-12-avoiding-npm-substitution-attacks/). 567 | --------------------------------------------------------------------------------