Protect dependency installation process with allow-scripts
@lavamoat/allow-scripts is a CLI tool for instructing your package manager to execute only the dependency lifecycle hooks specified in an allowlist.
Prerequisites
Section titled “Prerequisites”- Node.js LTS
- One of the following package managers:
- npm v8.0.0+
- Yarn v1.22.0+
- Yarn Berry v3 or above
- pnpm
Install
Section titled “Install”Install globally
Section titled “Install globally”We recommend using the globally installed @lavamoat/allow-scripts for the initial setup. This avoids triggering installation of your other dependencies before the setup and the allowlist is in place.
npm i -g @lavamoat/allow-scriptsBe sure to include the @lavamoat/ namespace in the package name.
Now without triggering an installation in the project you’re setting up, you can go to the project folder and run:
allow-scripts setupProject-local installation
Section titled “Project-local installation”Install as a project-local development dependency to enable contributors to execute allowed scripts.
- npm:
npm i -D @lavamoat/allow-scripts - Yarn:
yarn add -D @lavamoat/allow-scripts - pnpm:
pnpm add -D @lavamoat/allow-scripts
Note that installation of the dependency is likely to cause your other dependencies to be installed. You could install @lavamoat/allow-scripts globally and use it to set up a project without triggering installing dependencies before the setup and the allowlist is in place.
Initialization
Section titled “Initialization”The setup command will initialize your project for use with @lavamoat/allow-scripts.
- npm:
npm exec allow-scripts setup - Yarn:
yarn allow-scripts setup
Configuration
Section titled “Configuration”Configuration can be done automatically or manually.
Automatic Allow-listing
Section titled “Automatic Allow-listing”The auto command will generate and write a configuration to the lavamoat property of package.json.
- npm:
npm exec allow-scripts auto - Yarn:
yarn allow-scripts auto
Manual Allow-listing
Section titled “Manual Allow-listing”@lavamoat/allow-scripts’s configuration is stored in the lavamoat property of package.json within its allowScripts property.
The value is of type Record<PackageName, boolean> where PackageName is a dependency (with a #version suffix by default) which is either allowed or disallowed to run lifecycle scripts. To allow script execution, use a value of true; to disallow, use a value of false.
Items missing from the list will cause warnings so that you know when you might need to add a newly installed item to the list.
Example Configuration
Section titled “Example Configuration”{ "lavamoat": { "allowScripts": { "keccak#3.0.4": true, "rezeplayer>core-js#3.49.0": false, "some-package-denied-for-all-versions": false } }}Running Lifecycle Scripts
Section titled “Running Lifecycle Scripts”When invoked without a command (or with the run command), allow-scripts will execute all lifecycle scripts for the packages specified in @lavamoat/allow-scripts’s configuration:
- npm:
npm exec allow-scripts run - Yarn:
yarn allow-scripts run
allow-scripts will fail if it detects dependencies attempting to run scripts which haven’t yet been configured; you will be advised to run allow-scripts auto to rectify the situation.
Yarn plugin
Section titled “Yarn plugin”To comfortably work with Yarn Berry (specifically yarn v3 or above) it’s recommended that you use a simple plugin to execute allow-scripts after installation.
Yarn plugins are installed via public URLs.
yarn plugin import https://raw.githubusercontent.com/LavaMoat/LavaMoat/main/packages/yarn-plugin-allow-scripts/bundles/@yarnpkg/plugin-allow-scripts.jsShow Configured Packages
Section titled “Show Configured Packages”Use the list command (alias: debug) to print all information allow-scripts uses to populate and run the allowed scripts, including the list of changes it would make if allow-scripts auto was executed.
- npm:
npm exec allow-scripts list - Yarn:
yarn allow-scripts list
Usage Tips
Section titled “Usage Tips”Consider adding a setup lifecycle script for all your post-install steps. This can be just a regular script (no magic needed!). Also, it is a good place to add other post-processing commands you want to use.
In the future, when you add additional post-processing scripts, e.g. husky, you can add them to this setup script.
{ "scripts": { "setup": "npm install && npm exec allow-scripts && tsc -b" }}Mitigating bin script confusion
Section titled “Mitigating bin script confusion”Bin script confusion is a shell injection attack (wiki) where a dependency causes a malicious script to run by declaring a bin script (in package.json) matching an executable in the user’s PATH. ignore-scripts does not protect against this attack.
To enable protection against bin script confusion, use the --experimental-bins flag when executing allow-scripts.
What does --experimental-bins do?
Section titled “What does --experimental-bins do?”allow-scripts setupwill add a new configuration option to your project’s package manager RC file (.npmrc/.yarnrc) to disable automatic linkingbinscriptsallow-scripts autowill generate an allowlist ofbinscripts allowed for executionallow-scripts runwill link only the allowed scripts and replace disallowed scripts with a trivial executable that exits with a non-zero exit code.
When a disallowed bin script is attempted to be executed, the command will fail with an error providing guidance.