10 npm Security Best Practices. Avoid publishing secrets to the npm registry. Enforce the lockfile. Assess npm project health. Audit for vulnerabilities in open source dependencies. Use a local npm proxy. Responsibly disclose security vulnerabilities. Enable 2FA. Use npm author tokens.
Concerned about npm vulnerabilities? It is important to take npm security into account for both frontend, and backend developers. Open source security auditing is a crucial part of shifting security to the left, and npm package security should be a top concern, as we see that even the official npm command line tool has been found to be vulnerable.
In this cheat sheet edition, we’re going to focus on npm security and productivity tips for both open source maintainers and developers. So let’s get started with our list of 10 npm security best practices, starting with a classic mistake: people adding their passwords to the npm packages they publish!
Whether you’re making use of API keys, passwords or other secrets, they can very easily end up leaking into source control or even a published package on the public npm registry. You may have secrets in your working directory in designated files such as a .env
which should be added to a .gitignore
to avoid committing it to a SCM, but what happen when you publish an npm package from the project’s directory?
The npm CLI packs up a project into a tar archive (tarball) in order to push it to the registry. The following criteria determine which files and directories are added to the tarball:
.gitignore
or a .npmignore
file, the contents of the file are used as an ignore pattern when preparing the package for publication..npmignore
is published to the registry. This condition is a common source of confusion and is a problem that can lead to leaking secrets. Developers may end up updating the .gitignore
file, but forget to update .npmignore
as well, which can lead to a potentially sensitive file not being pushed to source control, but still being included in the npm package.Another good practice to adopt is making use of the files
property in package.json, which works as a whitelist and specifies the array of files to be included in the package that is to be created and installed (while the ignore file functions as a blacklist). The files
property and an ignore file can both be used together to determine which files should explicitly be included, as well as excluded, from the package. When using both, the former the files
property in package.json takes precedence over the ignore file.
When a package is published, the npm CLI will verbosely display the archive being created. To be extra careful, add a --dry-run
argument to your publish command in order to first review how the tarball is created without actually publishing it to the registry.
In January 2019, npm shared on their blog that they added a mechanism that automatically revokes a token if they detect that one has been published with a package.
We embraced the birth of package lockfiles with open arms, which introduced: deterministic installations across different environments, and enforced dependency expectations across team collaboration. Life is good! Or so I thought… what would have happened had I slipped a change into the project’s package.json file but had forgotten to commit the lockfile along side of it?
Both Yarn, and npm act the same during dependency installation . When they detect an inconsistency between the project’s package.json
and the lockfile, they compensate for such change based on the package.json
manifest by installing different versions than those that were recorded in the lockfile.
This kind of situation can be hazardous for build and production environments as they could pull in unintended package versions and render the entire benefit of a lockfile futile.
Luckily, there is a way to tell both Yarn and npm to adhere to a specified set of dependencies and their versions by referencing them from the lockfile. Any inconsistency will abort the installation. The command line should read as follows:
yarn install --frozen-lockfile
.npm ci
.The npm CLI works with package run-scripts. If you’ve ever run npm start
or npm test
then you’ve used package run-scripts too. The npm CLI builds on scripts that a package can declare, and allows packages to define scripts to run at specific entry points during the package’s installation in a project. For example, some of these script hook entries may be postinstall
scripts that a package that is being installed will execute in order to perform housekeeping chores.
With this capability, bad actors may create or alter packages to perform malicious acts by running any arbitrary command when their package is installed. A couple of cases where we’ve seen this already happening is the popular eslint-scope incident that harvested npm tokens, and the crossenv incident, along with 36 other packages that abused a typosquatting attack on the npm registry.
Apply these best practices in order to minimize the malicious module attack surface:
Always vet and perform due-diligence on third-party modules that you install in order to confirm their health and credibility.
--ignore-scripts
suffix to disable the execution of any scripts by third-party packages.ignore-scripts
to your .npmrc
project file, or to your global npm configuration.Rushing to constantly upgrade dependencies to their latest releases is not necessarily a good practice if it is done without reviewing release notes, the code changes, and generally testing new upgrades in a comprehensive manner. With that said, staying out of date and not upgrading at all, or after a long time, is a source for trouble as well.
The npm CLI can provide information about the freshness of dependencies you use with regards to their semantic versioning offset. By running npm outdated
, you can see which packages are out of date:
Dependencies in yellow correspond to the semantic versioning as specified in the package.json manifest, and dependencies colored in red mean that there’s an update available. Furthermore, the output also shows the latest version for each dependency.
Between the variety of Node.js package managers, and different versions of Node.js you may have installed in your path, how do you verify a healthy npm installation and working environment? Whether you’re working with the npm CLI in a development environment or within a CI, it is important to assess that everything is working as expected.
Call the doctor! The npm CLI incorporates a health assessment tool to diagnose your environment for a well-working npm interaction. Run npm doctor
to review your npm setup:
node_modules
, and on the folder used for package cache.The npm ecosystem is the single largest repository of application libraries amongst all the other language ecosystems. The registry and the libraries in it are at the core for JavaScript developers as they are able to leverage work that others have already built and incorporate it into their code-base. With that said, the increasing adoption of open source libraries in applications brings with it an increased risk of introducing security vulnerabilities.
Many popular npm packages have been found to be vulnerable and may carry a significant risk without proper security auditing of your project’s dependencies. Some examples are npm request, superagent, mongoose, and even security-related packages like jsonwebtoken, and npm validator.
Security doesn’t end by just scanning for security vulnerabilities when installing a package but should also be streamlined with developer workflows to be effectively adopted throughout the entire lifecycle of software development, and monitored continuously when code is deployed.
Scanning for security vulnerabilities with Snyk, use:
$ npm install -g snyk $ snyk test
When you run a Snyk test, Snyk reports the vulnerabilities it found and displays the vulnerable paths so you can track the dependency tree to understand which module introduced a vulnerability. Most importantly, Snyk provides you with actionable remediation advise so you can upgrade to a fixed version through an automated pull request that Snyk opens in your repository, or apply a patch that Snyk provides to mitigate the vulnerability if no fix is available. Snyk provides a smart upgrade by recommending the minimal semver-upgrade possible for the vulnerable package.
The security work doesn’t end there.
What about security vulnerabilities found in an application’s dependency after the application has been deployed? That’s where the importance of security monitoring and tight integration with the project’s development lifecycle comes in.
We recommend integrating Snyk with your source code management (SCM) system such as GitHub or GitLab so that Snyk actively monitors your projects and:
If you can’t integrate Snyk with an SCM, it is possible to monitor snapshots of your projects as sent from the Snyk CLI tool as well, by simply running:
$ snyk monitor
The npm registry is the biggest collection of packages that is available for all JavaScript developers and is also the home of the most of the Open Source projects for web developers. But sometimes you might have different needs in terms of security, deployments or performance. When this is true, npm allows you to switch to a different registry:
When you run npm install
, it automatically starts a communication with the main registry to resolve all your dependencies; if you wish to use a different registry, that too is pretty straightforward:
npm set registry
to set up a default registry.–registry
for one single registry.Verdaccio is a simple lightweight zero-config-required private registry and installing it is as simple as follows:
$ npm install --global verdaccio
Hosting your own registry was never so easy! Let’s check the most important features of this tool:
It is fairly simple to run:
$ verdaccio --config /path/config --listen 5000
If you use verdaccio for a local private registry, consider having a configuration for your packages to enforce publishing to the local registry and avoid accidental publishing by developers to a public registry. To achieve this add the following to package.json:
“publishConfig”: {
“registry”: “https://localhost:5000”
}
Your registry is running—ya !! Now, to publish a package just use the npm command npm publish
and it is ready for you to share it with the world.
When security vulnerabilities are found, they pose a potentially serious threat if publicly disclosed without prior warning or appropriate mitigation available for users to protect themselves.
It is recommended that security researchers follow a responsible disclosure program, which is a set of processes and guidelines that aims to connect the researchers with the vendor or maintainer of the vulnerable asset, in order to convey the vulnerability, it’s impact and applicability. Once the vulnerability is correctly triaged, the vendor and researcher coordinate a fix and a publication date for the vulnerability in an effort to provide an upgrade-path or remediation for affected users before the security issue is made public.
Security is too important to be an afterthought or handled unethically. At Snyk, we deeply value the security community and believe that a responsible disclosure of security vulnerabilities in open source packages helps us ensure the security and privacy of the users.
Snyk’s security research team regularly collaborates with the community for bug bounties, such as the case with f2e-server that resulted in hundreds of community disclosures, as well as Snyk’s very close partnership with academic researchers such as Virginia Tech to provide security expertise and the ability to coordinate with vendors and community maintainers.
We invite you to collaborate with us and offer our help with the disclosure process:
In October 2017, npm officially announced support for two-factor authentication (2FA) for developers using the npm registry to host their closed and open source packages.
Even though 2FA has been supported on the npm registry for a while now, it seems to be slowly adopted with one example being the eslint-scope incident in mid-2018 when a stolen developer account on the ESLint team lead to a malicious version of eslint-scope being published by bad actors.
** URGENT SECURITY WARNING ** Please share.
Today, version 3.7.2 of eslint-scope (https://t.co/Gkc9XhDRN6) was found to contain malicious code that steals your NPM credentials. Take action now if you are using version 3.7.2.
Snyk DB entry: https://t.co/dAhhA3cZQP
— Snyk (@snyksec) July 12, 2018
The registry supports two modes for enabling 2FA in a user’s account:
Equip yourself with an authentication application, such as Google Authentication, which you can install on a mobile device, and you’re ready to get started. One easy way to get started with the 2FA extended protection for your account is through npm’s user interface, which allows enabling it very easily. If you’re a command line person, it’s also easy to enable 2FA when using a supported npm client version (>=5.5.1):
$ npm profile enable-2fa auth-and-writes
Follow the command line instructions to enable 2FA, and to save emergency authentication codes. If you wish to enable 2FA mode for login and profile changes only, you may replace the auth-and-writes
with auth-only
in the code as it appears above.
Every time you log in with the npm CLI, a token is generated for your user and authenticates you to the npm registry. Tokens make it easy to perform npm registry-related actions during CI and automated procedures, such as accessing private modules on the registry or publishing new versions from a build step.
Tokens can be managed through the npm registry website, as well as using the npm command line client. An example of using the CLI to create a read-only token that is restricted to a specific IPv4 address range is as follows:
$ npm token create --read-only --cidr=192.0.2.0/24
To verify which tokens are created for your user or to revoke tokens in cases of emergency, you can use npm token list
or npm token revoke
respectively.
Naming a module is the first thing you might do when creating a package, but before defining a final name, npm defines some rules that a package name must follow:
Even if you follow these rules, be aware that npm uses a spam detection mechanism when publishing new packages, based on score and whether a package name violates the terms of the service. If conditions are violated, the registry might deny the request.
Typosquatting is an attack that relies on mistakes made by users, such as typos. With typosquatting, bad actors could publish malicious modules to the npm registry with names that look much like existing popular modules.
We have been tracking tens of malicious packages in the npm ecosystem; they have been seen on the PyPi Python registry as well. Perhaps some of the most popular incidents have been for cross-env, event-stream, and eslint-scope.
One of the main targets for typosquatting attacks are the user credentials, since any package has access to environment variables via the global variable process.env
. Other examples we’ve seen in the past include the case with event-stream, where the attack targeted developers in the hopes of injecting malicious code into an application’s source code.
To reduce the risk of such attacks you might do the following:
npm info
to fetch more information about contributors and latest versions.–ignore-scripts
to reduce the risk of arbitrary command execution. For example: npm install my-malicious-package --ignore-scripts
Be sure to print out the cheat sheet and pin it up somewhere to remind you of some of the npm security best practices you should follow if you’re a javascript developer, or just enjoy using npm for fun.
☞ 10 Node Frameworks to Use in 2019
☞ Machine Learning In Node.js With TensorFlow.js
☞ Full Stack Developers: Everything You Need to Know
☞ MEAN Stack Tutorial MongoDB, ExpressJS, AngularJS and NodeJS
☞ Build a web scraper with Node
Originally published by Liran Tal, Juan Picado at https://snyk.io
#npm #node-js #security