@ministryofjustice/hmpps-npm-script-allowlist
v0.0.4
Published
A tool to restrict npm scripts from running unless as part of an allowlist
Readme
@ministryofjustice/hmpps-npm-script-allowlist
This package aims to restrict npm scripts from running unless as part of a predefined allowlist.
Status
This library is currently: ready to trial.
Teams are welcome to trial this library. Please provide feedback via slack to the #typescript channel.
Migrating existing projects
Automatically installing the library
The package will self install and initialised by running via npx:
npx @ministryofjustice/hmpps-npm-script-allowlist
Note: The project needs to be initialised before use - solely adding the library will not apply the required changes. Once the project has been initialised and changes commited, other developers should be able to benefit from the library without further local initialisation.
How this works
The library can be applied to a service by running npx @ministryofjustice/hmpps-npm-script-allowlist
This will:
- Set some sensible defaults in
.npmrcto prevent execution of scripts - Install the package
- Add a default configuration file
- Add a new npm script called
setup - Run the tool, which will likely fail allowing the developer to complete configuration
The tool can then be configured with a list of packages that should be allowed to run scripts post install. Entries can target an exact version, a semver range, or the package path with no version to match all installed versions at that path.
To work with the project after that:
npm installwill install packages but no longer executes any scripts due to the defaults set in.npmrcnpm run setuprunsnpm ci(without scripts) and then executes only those scripts that have been explicitly allowed.
A manual step is required to move CI and docker over to use npm run setup instead of npm ci
Configuration
To configure the tool update ./allowed-scripts.mjs and set ALLOW or FORBID to each entry in allowed-scripts.mjs, e.g::
import configureAllowedScripts from '@ministryofjustice/hmpps-npm-script-allowlist/index.mjs'
export default configureAllowedScripts({
allowlist: {
"node_modules/@parcel/watcher@^2.5.1": "ALLOW",
"node_modules/cypress@~14.5.4": "FORBID",
"node_modules/[email protected]": "ALLOW",
"node_modules/[email protected]": "FORBID",
"node_modules/unrs-resolver": "ALLOW"
},
})(The tool will play back the configuration and highlight versions which need to be added so an initial version can easily be copy/pasted in.)
By default hmpps-npm-script-allowlist will only manage and run the following scripts:
preinstallinstallpreparepostinstall
Scripts bound to other lifecycles will not be executed.
This list can be expand by specifying the following options in ./allowed-scripts.mjs:
localScriptsToRun: The list of the current service's scripts to run post installdependencyScriptsToRun: The list of script's belonging to dependencies, that should be allowed to run post install
Doesn't lavamoat do the same thing?
This is heavily inspired by lavamoat's allowscripts.
This works slightly differently:
- Scripts need to be explicitly configured either to be included or not or the script will fail
- This supports using the explicit version in the package-lock.json to key whether a script should run or not, rather than just the name of the package
- It provides some extra contextual information about the packages that need to be allowlisted - details about the script and when the package was published.
Example output:
Reading configuration from some-project/.allowed-scripts.mjs
Current configuration: {
"node_modules/@parcel/[email protected]": "RUN",
"node_modules/[email protected]": "<REMOVED>",
"node_modules/[email protected]": "<MISSING>",
"node_modules/[email protected]": "RUN",
"node_modules/[email protected]": "<MISSING>",
"node_modules/[email protected]": "RUN"
}
ACTION REQUIRED:
Explicitly ALLOW/FORBID the following:
* node_modules/[email protected] (package published: 2025-08-07 18:35)
scripts:
postinstall: node dist/index.js --exec install
* node_modules/[email protected] (package published: 2023-08-21 17:24)
scripts:
install: node-gyp rebuild
ACTION REQUIRED:
Remove configuration for the following packages as they are no longer present:
* node_modules/[email protected]
Copy the "Current Configuration" from above and use it to update: some-project/.allowed-scripts.mjs.
* Remove any entries that are <REMOVED>
* Evaluate any entries marked <MISSING>. ALLOW or FORBID depending on whether these entries have scripts that are safe and required to run.How can I tell whether a script is safe to allow/forbid?
This generally requires a bit of investigation!
- There's a list of common vetted packages at specific versions in the hmpps-template-typescript project here.
- One of the developers of lavamoat has curated a list of scripts which you likely can forbid here
- Otherwise you really need to determine what the specific flagged
preinstall,install,prepareorpostinstallscripts are doing. - If in doubt please ask the #typescript channel for help
Testing
Export a local package:
npm run lint && npm run build && npm run test && npm pack --pack-destination ~
cd to the project you want to test it on, and install:
npm install --ignore-scripts -D ~/ministryofjustice-hmpps-npm-script-allowlist-xxx.tgz
To test the init script:
npx -p ~/ministryofjustice-hmpps-npm-script-allowlist-0.0.1-alpha.2.tgz hmpps-npm-script-allowlist
To test the command directly:
./node_modules/.bin/hmpps-npm-script-run-allowlist
