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
- Node.js LTS
- One of the following package managers:
- npm v8.0.0+
- Yarn v1.22.0+
- Yarn Berry v3 or above
Install
- npm:
npm i -D @lavamoat/allow-scripts - Yarn:
yarn 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.
Setup
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
Configuration can be done automatically or manually.
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
@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 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 a warnings so that you know when you might need to add a newly installed item to the list.
Example Configuration
{ "lavamoat": { "allowScripts": { "keccak": true, "core-js": false } }}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
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
Use the list command to print information about configured packages and scripts, specifying allowed and disallowed packages.
- npm:
npm exec allow-scripts list - Yarn:
yarn allow-scripts list
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
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?
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.