Major npm incident: how to protect projects from supply-chain attacks
In July 2025, the npm ecosystem faced one of the largest supply-chain attacks in its history. Attackers gained access to maintainers' accounts of popular packages and published malicious versions that millions of developers installed.
What happened
Compromised packages:
eslint-config-prettier— 30M+ downloads/week. Malicious versions: 8.10.1, 9.1.1, 10.1.6, 10.1.7eslint-plugin-prettiersynckit@pkgr/corenapi-postinstallis— 2.8M downloads/week. Malicious versions: 3.3.1–5.0.0
How the attack unfolded:
- Phishing via a typosquatted domain
npnjs.com→ maintainers entered their credentials. - Attackers gained access and published malicious builds directly to npm.
- The malicious code was disguised as a
postinstallscript that downloaded a DLL or opened a WebSocket backdoor. - Releases bypassed GitHub repositories — typical commit monitoring did not help.
Total reach — over 180M downloads per week.
Sources:
How to defend against similar attacks
1. Pin exact versions
In package.json:
"eslint-config-prettier": "10.1.0"
Instead of:
"eslint-config-prettier": "^10.1.0"
Command for npm to record exact versions by default for future installs:
npm config set save-exact true
And in .npmrc (in the repository) you can additionally enforce this:
save-exact=true
How to quickly pin versions across the whole project
If your package.json already uses ^ or ~, you can quickly remove them and pin exact numbers.
For npm:
npx npm-check-updates -f "/.*/" --removeRange --upgrade
npm-check-updatesis a utility for managing dependency versions.- The
--removeRangeflag removes^and~from all entries.
npm-check-updates does not read package-lock.json. It operates only on your package.json, replacing dependency versions with the latest from npm (respecting filters and constraints you provide). If you keep your package-lock.json in the repository, it is safer to pin versions directly from the lockfile. Here's a working Node.js script that takes exact versions from package-lock.json and writes them to package.json without ^ and ~.
2. Use lockfiles
Commit package-lock.json to your repository. This pins all dependencies, including transitive ones.
3. Enable dependency audits
npm audit
4. Minimize postinstall scripts
Avoid dependencies that execute code during installation unless absolutely necessary.
5. Enable 2FA for your npm account
This makes account takeover harder even if a password leaks.
6. Verify emails and domains
Do not follow links from “official” emails until you verify the address. The difference between npmjs.com and npnjs.com is just one letter.
Conclusion
Supply-chain attacks are becoming more frequent, and even a popular package with a long history can be compromised. Minimizing automatic updates, controlling dependencies, and staying vigilant are key steps to protecting your projects.
Read next
- February 12, 2026

Website Redesign in the Age of AI and the End of Traditional SEO
The story of another redesign of my website, GSAP animations, and why design no longer drives search traffic in the age of AI.
- January 9, 2026

Traffic Report: December 2025 – January 2026
Website traffic over the last 30 days — a short report and observations.
