|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: Secure npm installs with --ignore-scripts |
| 4 | +date: 2026-05-15 15:15:09 |
| 5 | +excerpt: How to make npm installs safer with --ignore-scripts. |
| 6 | +categories: npm scripts security |
| 7 | +--- |
| 8 | + |
| 9 | +This post explains how to make `npm install` safer with `--ignore-scripts`: |
| 10 | + |
| 11 | +- [Problem](#problem) |
| 12 | +- [Disable Lifecycle Scripts](#disable-lifecycle-scripts) |
| 13 | +- [Global Disable](#global-disable) |
| 14 | + |
| 15 | +## Problem |
| 16 | + |
| 17 | +When you run `npm install`, package lifecycle scripts can execute arbitrary shell commands on your machine. |
| 18 | + |
| 19 | +For example, a `package.json` may contain: |
| 20 | + |
| 21 | +```json |
| 22 | +{ |
| 23 | + "scripts": { |
| 24 | + "postinstall": "echo do something malicious..." |
| 25 | + } |
| 26 | +} |
| 27 | +``` |
| 28 | + |
| 29 | +This is how attacks like the [Shai-Hulud worm](https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/) work. |
| 30 | + |
| 31 | +A malicious or compromised dependency can: |
| 32 | + |
| 33 | +- steal secrets or tokens |
| 34 | +- install malware or backdoors |
| 35 | +- access or modify files on your machine |
| 36 | +- tamper with build artifacts |
| 37 | + |
| 38 | +## Disable Lifecycle Scripts |
| 39 | + |
| 40 | +Ignore lifecycle scripts during install: |
| 41 | + |
| 42 | +```sh |
| 43 | +npm install --ignore-scripts |
| 44 | +``` |
| 45 | + |
| 46 | +This downloads dependencies normally, but prevents lifecycle hooks from executing: |
| 47 | + |
| 48 | +- `preinstall` |
| 49 | +- `install` |
| 50 | +- `postinstall` |
| 51 | +- `prepare` |
| 52 | + |
| 53 | +This is useful when: |
| 54 | + |
| 55 | +- auditing unfamiliar repositories |
| 56 | +- testing untrusted dependencies |
| 57 | +- reducing supply-chain attack surface |
| 58 | +- running installs in CI |
| 59 | + |
| 60 | +> One caveat of disabling scripts is that it can break packages that rely on native builds or binary downloads (e.g., `bcrypt`, `esbuild`, `sqlite3`, etc.). |
| 61 | +
|
| 62 | +## Global Disable |
| 63 | + |
| 64 | +To disable lifecycle scripts globally: |
| 65 | + |
| 66 | +```sh |
| 67 | +npm config set ignore-scripts true |
| 68 | +``` |
| 69 | + |
| 70 | +Verify the current setting: |
| 71 | + |
| 72 | +```sh |
| 73 | +npm config get ignore-scripts |
| 74 | +``` |
0 commit comments