Four lines in ~/.npmrc block the most common npm supply chain attacks before they execute. Setup takes 30 seconds. This is the bare-minimum defense for anyone letting Claude Code or Cursor run npm install on their machine.
These four lines are on my laptop right now. I added them the morning the axios news broke and forgot about them. Since then, every npm install Claude Code has run on my machine, across five side projects, has skipped lifecycle scripts by default. Zero breakage. Zero effort.
# ~/.npmrc
ignore-scripts=true
save-exact=true
audit-level=moderate
fund=false
In 2025, attackers published 454,648 malicious npm packages — roughly half a million in a single year (Sonatype Open Source Malware Index, 2026). The four lines above block the most common payload mechanism (lifecycle scripts) for every project on your laptop, including whatever Claude Code ran at 2am last night.
Why is your default npm setup unsafe in 2026?
npm ships with lifecycle scripts enabled by default. That means any package, direct or transitive, can execute arbitrary code on your machine during npm install — before you ever type require(). Over 99% of all open source malware now targets npm.
Here's the same attack pattern, compressed across eight years:
| Year | Incident | Payload vector |
|---|---|---|
| 2018 | event-stream (Bitcoin wallet stealer, 2M/wk) | postinstall |
| 2025 Sep | Shai-Hulud worm, 18 packages, 2.6B/wk downloads | postinstall |
| 2026 Mar | axios@1.14.1 RAT, 100M/wk downloads | postinstall |
Three incidents across eight years. Same mechanism every time. npm's official response each time is to unpublish the package and write a blog post. No structural change to how postinstall works.
The uncomfortable part: 84% of developers use AI coding tools, and 41% of code written in 2025 was AI-generated or AI-assisted. AI agents install packages at machine speed, with approval fatigue doing the rest. The human review step that used to catch weird dependencies has already been deleted from most workflows.
What each line does
ignore-scripts=true
Disables preinstall, install, and postinstall lifecycle scripts for every npm install. The OWASP NPM Security Cheat Sheet calls this the single most effective mitigation against malicious or compromised packages. The axios@1.14.1 RAT, the Shai-Hulud worm, event-stream's Bitcoin stealer — all needed this mechanism to execute. Turn it off globally and the default delivery vehicle is gone.
save-exact=true
Pins exact versions in package.json whenever you add a package. Without it, npm install axios writes "axios": "^1.14.0", a caret range that resolves to 1.14.1 on the next clean install. With save-exact=true, the same command writes "axios": "1.14.0". A hijacked patch release cannot silently promote itself into your lockfile.
audit-level=moderate
Raises npm install exit code when known CVEs of moderate or higher severity are present. Default behavior is warn-only. This flag makes audit block instead — which means CI or Claude Code sessions fail loud rather than scrolling past.
fund=false
Removes the "N packages are looking for funding" message from every install. Cosmetic, but it matters. When your install output is 80% funding notices, the warnings that actually matter (audit, deprecation, peer dependency conflicts) get buried. Signal hygiene is a security layer.
Verify your config:
npm config get ignore-scripts save-exact audit-level fund
Expected output: true, true, moderate, false.
Why does this work for most npm attacks?
The dominant payload pattern in 2025 and 2026 npm attacks is a lifecycle script that runs during install. Disabling those scripts breaks the default delivery vehicle.
| Attack vector | Real example | Line that blocks it |
|---|---|---|
| postinstall RAT | axios@1.14.1 (2026) | ignore-scripts=true |
| Silent minor/patch hijack | Maintainer account takeover | save-exact=true |
| Known CVE buried as warning | Any reported advisory | audit-level=moderate |
| Warning fatigue hiding alerts | Every install, all day | fund=false |
What does this NOT protect against?
Honest boundaries. This config blocks the most common vector, not every vector:
Malicious code in the package's main module. Anything that runs on require() or import is unaffected by ignore-scripts. If the package is actively imported by your code, the payload runs at runtime.
Toolchain exploits. --ignore-scripts stops npm lifecycle hooks, but git still runs during install, and external binaries still execute if the install process invokes them.
Typosquatting and slopsquatting. AI assistants sometimes hallucinate package names that attackers have preemptively registered. OWASP flags this as the fastest-growing npm attack class in 2026.
Packages already in node_modules. The four lines only protect future installs. Clean rebuild recommended: rm -rf node_modules package-lock.json && npm install.
Roughly 20% of recent high-impact npm malware executes outside lifecycle scripts through runtime require() or compromised main modules. Treat .npmrc as necessary-but-not-sufficient.
What breaks when you set ignore-scripts=true?
A small set of packages genuinely need lifecycle scripts to compile native binaries or download platform assets. The usual suspects: bcrypt, node-sass, sharp, esbuild, puppeteer, and canvas. You will notice immediately because they fail loud, not silent.
Fix per-package:
# Install normally, then rebuild the one package that needs it
npm install sharp
npm rebuild sharp
For projects with multiple native-compile dependencies, use an allow-list:
npm install --save-dev @lavamoat/allow-scripts
npx allow-scripts auto
npx allow-scripts
| Package | Why it needs scripts |
|---|---|
bcrypt |
Native C++ compilation |
sharp |
Binary download + native bindings |
node-sass |
LibSass native build |
esbuild |
Platform binary download |
puppeteer |
Chromium download |
canvas |
Cairo/Pango native bindings |
Ninety percent of projects never hit any of these. The ones that do fail on the first CI run after the config change, and you fix them once.
Upgrading to hook-based defense
~/.npmrc is the user-scoped floor. The next layer is process-level enforcement: intercepting every npm install Claude Code tries to run, auditing it before the command executes, and blocking the call if it's missing --ignore-scripts or pointing at a new unreviewed dependency.
With 41% of all code now AI-generated or AI-assisted, the agent — not the human — is the primary npm install trigger. That's a PreToolUse hook in .claude/settings.json.
The hook post covers the three-layer setup: PreToolUse audit, PostToolUse lockfile diff, and CLAUDE.md enforcement rules.
FAQ
Will ignore-scripts=true break my builds?
Usually no for pure-JavaScript dependencies, which is 90%+ of a typical React or Node project. Yes for native-compile packages like bcrypt, sharp, and esbuild. Fix is npm rebuild <pkg> per package or @lavamoat/allow-scripts for a team-wide allow-list.
Should I commit .npmrc to my repo?
Personal config goes in ~/.npmrc (never committed, user defaults). Project-level .npmrc at the repo root can be committed as long as it contains no secrets. Registry auth tokens belong only in ~/.npmrc, never in the repo.
Does this work for pnpm and yarn?
.npmrc is shared. pnpm reads ignore-scripts=true natively. Yarn classic also reads .npmrc. Yarn Berry uses .yarnrc.yml instead, and the equivalent setting is enableScripts: false. Bun also honors .npmrc.
Is npm audit still useful if I set audit-level=moderate?
Yes, and it becomes more useful. The flag changes audit from warn-mode to block-mode on CVEs at moderate severity or higher. Audit still only catches published CVEs. For zero-days, you need the hook layer from the hooks post.
Try it now: Open a terminal and run:
echo -e "ignore-scripts=true\nsave-exact=true\naudit-level=moderate\nfund=false" >> ~/.npmrc
Verify with npm config get ignore-scripts save-exact audit-level fund. Total time: under 30 seconds.
Ready for the process-level defense? Read → Stop npm Supply Chain Attacks with Claude Code Hooks.
Originally published on ShipWithAI. I write about Claude Code workflows, AI-assisted development, and shipping software faster with structured AI.
Top comments (0)