What actually runs at npm install time

npm v12 turned install scripts off by default, so you now approve them one at a time. This is what that approval queue actually looks like across the registry, measured every day.

Sample of 3,238 packages, 732 of them scoped, resolved at 100% coverage. Rebuilt 2026-09-24 by npm-script-lens, run unmodified. Raw output: census.json.

28run an install script, of 3,238
0.86%of the sample
18score HIGH
255.5Ma week · esbuild

Sticking to popular packages does not help

0.0%0.7%1.4%Top 100: 1 of 100 (1.00%), floor 101.9M/week1.00%Top 1001 of 100 · ≥101.9M/wkTop 500: 4 of 500 (0.80%), floor 11.3M/week0.80%Top 5004 of 500 · ≥11.3M/wkTop 1,000: 7 of 1,000 (0.70%), floor 1.9M/week0.70%Top 1,0007 of 1,000 · ≥1.9M/wkTop 2,000: 18 of 2,000 (0.90%), floor 139.0K/week0.90%Top 2,00018 of 2,000 · ≥139.0K/wkFull sample: 28 of 3,238 (0.86%), floor 4/week0.86%Full sample28 of 3,238 · ≥4/wk
Share of each cumulative top-N cut that runs an install script. If install scripts clustered in the unmaintained tail, the left-hand columns would be shorter. They are not.
Show the numbers
SampleDownload floorRun an install scriptShareHIGH or MEDIUM
Top 100101.9M/week1 of 1001.00%1
Top 50011.3M/week4 of 5000.80%3
Top 1,0001.9M/week7 of 1,0000.70%4
Top 2,000139.0K/week18 of 2,0000.90%12
Full sample4/week28 of 3,2380.86%18

The approval queue

Every package in the sample that runs something, ordered by weekly downloads. None of this is an accusation: these are well-known packages fetching a prebuilt binary or building a native addon. They are simply the ones you are now asked to approve, and "what does it actually do" is a per-package question.

PackageDownloads/wkScript CommandRiskSignals
esbuild 0.28.2255.5Mpostinstallnode install.jsHIGHenv, exec, fs, net
unrs-resolver 1.12.251.3Mpostinstallnode postinstall.jsSAFEnone
@sentry/cli 3.8.023.6Mpostinstallnode ./scripts/install.jsHIGHenv, exec, fs, net
workerd 1.20260924.119.0Mpostinstallnode install.jsHIGHenv, exec, fs, net
vue-demi 0.14.108.0Mpostinstallnode -e "try{require('./scripts/postinstall.js')}catch(e){}"LOWfs
bufferutil 4.1.06.8Minstallnode-gyp-buildHIGHbin, env, exec
mongodb-memory-server 11.3.02.1Mpostinstallnode ./postinstall.jsSAFEnone
node 26.9.01.4Mpreinstallnode installArchSpecificPackageSAFEnone
tree-sitter-json 0.24.81.1Minstallnode-gyp-buildHIGHbin, env, exec
oracledb 7.0.1806.3Kinstallnode package/install.jsHIGHobf
@pulumi/docker-build 0.0.22806.2Kinstallnode scripts/install-pulumi-plugin.js resource docker-build 0.0.22HIGHexec
tree-sitter-typescript 0.23.2750.2Kinstallnode-gyp-buildHIGHbin, env, exec
stream-chat 9.53.0496.2Kpostinstallnode -e "require('fs').existsSync('scripts/install-husky.mjs') && import('./scripts/install-husky.mjs')"SAFEnone
@azure/msal-node-extensions 5.5.1391.3Kinstallexit 0SAFEnone
redis-memory-server 0.17.1297.2Kpostinstallnode ./scripts/postinstallHIGHenv, exec, fs, net
react-native-enriched-markdown 1.0.2214.0Kpostinstallnode postinstall.mjsHIGHenv, exec, exec-local, fs, net
classic-level 3.0.0171.7Kinstallnode-gyp-buildHIGHbin, env, exec
@microsoft/m365agentstoolkit-cli 1.1.17158.2Kpostinstallnode deletePS1.jsHIGHexec
nodent-runtime 3.2.1113.4Kinstallnode build.jsHIGHfs, obf
node-jq 6.3.1102.9Kpreinstallnpm run install-binaryHIGHenv, exec, net
rete 2.0.694.7Kpostinstallnode postinstall.jsSAFEnone
zenstack 2.22.365.8Kpostinstallnode bin/post-install.jsLOWenv
tree-sitter-yaml 0.5.058.2Kinstallnode-gyp rebuildHIGHexec, gyp
playwright-ws-trace 1.1.222.8Kpostinstallnode scripts/postinstall.jsLOWenv, fs
swc-plugin-import-meta-env 1.16.221.9Kpreinstallnpx only-allow pnpmHIGHexec, net
bcrypto 5.5.217.3Kinstallnode-gyp rebuildHIGHexec, gyp
better-auth-studio 1.1.56.3Kpostinstallnode scripts/postinstall.jsSAFEnone
@qooxdoo/framework 7.9.34.1Kpreinstallnode ./addGitHookHIGHenv, exec, fs

What they reach for

execexec: 4141envenv: 1313fsfs: 1313netnet: 1212binbin: 44gypgyp: 44obfobf: 22exec-localexec-local: 22
Capability classes seen across the scripted packages. Capability, not intent: exec means the script spawns a process, which is exactly what a native build does.