Top
Best
New

Posted by naugtur 9/9/2025

You too can run malware from NPM (I mean without consequences)(github.com)
195 points | 114 commentspage 2
p2detar 9/9/2025|
I’ve been out of the loop with npm for a while, but are there still no package namespaces?
stby 9/9/2025||
I am also out of the loop here, how would namespaces have helped?
diggan 9/9/2025|||
Namespaces have existed since ~2016 at least in npm, but since it's not enforced and people want "nice looking" package names, the ecosystem still hasn't fully embraced it. It seems like more and more projects are using them (probably because all "good" names are already taken), but probably way less than half of all popular packages are scoped/namespaced.
keysdev 9/9/2025||
Well there is jsr now....
uallo 9/9/2025||
https://docs.npmjs.com/about-scopes
herpdyderp 9/9/2025||
I’m intrigued but is that compartmentalization not incredibly expensive?
naugtur 9/9/2025|
It's within the same process and realm (window) It has a cost, but it's nothing compared to putting every dependency of a large app in a separate iframe/process and figure out a way for them to communicate.
cluckindan 9/9/2025||
Have you tried to find ways to break it?

Plenty of objects in the browser API contain references to things that could be used to defeat the compartmentalization.

If one were to enumerate all properties on window and document, how many would be objects with a reference back to window, document or some API not on the allowed list?

cowbertvonmoo 9/9/2025||
I maintain ses, the compartment primitive LavaMoat relies on. The ses shim for hardenedjs.org creates compartments that deny guest code the ability to inspect the true global object or lexically reference any of its properties. By default, each compartment only sees the transitively frozen intrinsics like Array and Object, and no way to reach the genuine evaluators. The compartment traps the module loader as well, so you can only import modules that are explicitly injected. That leaves a lot of room for the platform to make mistakes and endow the compartment with gadgets, but also gives us a place to stand to mount a defense that is not otherwise prohibitively expensive.
j45 9/9/2025||
How does one avoid malware in npm specifically?

Makes me not want to use the ecosystem, which isn’t always possible.

pimterry 9/9/2025||
This attack is pretty bad, but as shown by the tiny ROI for the attacker mentioned in this article (about $500 so far: https://intel.arkm.com/explorer/entity/61fbc095-f19b-479d-a0...) this really isn't quite as ecosystem-catastrophic as it sounds, for a few reasons:

* Major attacks on large packages like this are caught fairly quickly - a few hours in this case - making the vulnerable window _relatively_ small.

* NPM locks installed dependencies by default, against both the version & a hash of the content, so you'll only install the new malicious version if you happen to be adding or updating this dependency specifically within the window this version is still live. It's effectively sort-of TOFU. If even you ran `npm install` in a project already using this dependency in the specific window it was live, you will not normally install the malicious version.

* There's quite a few tools to help mitigate the risk here, like https://socket.dev and npq (https://github.com/lirantal/npq).

As one datapoint, look at the download stats for the affected Chalk package for example (https://www.npmjs.com/package/chalk?activeTab=versions) - the vast majority of installs were not installing the latest version anyway.

There are caveats to this: e.g. you can use npm without a lockfile, in which case a fresh local install can pull down unexpected versions, or you could be manually updating/adding a different package which happens to depend on an affected package (which might trigger a lockfile update, which might then fetch the latest version of the subdependency) during the vulnerable window, or of course it's totally possible you might install the package for the first time at the precisely wrong moment, etc etc.

This is definitely bad, and could have been extremely disastrous if it wasn't caught. But in practice, npm & the ecosystem have put in quite a few protections that do help to _mostly_ mitigate these kind of risks in typical use cases (but not completely, and there's definitely plenty more work to do!) and it's certainly not the case that millions of JS developers & projects were all catastrophically pwned today.

naugtur 9/9/2025||
Very good summary.

Most other ecosystems are as vulnerable if not more, they just lack the scale.

OP, The malware is coming to the ecosystem you prefer. Give it time.

mapmeld 9/9/2025|||
'npm install' and 'pip install' can both run scripts on your computer. Both ecosystems have this risk and loose monitoring, so there are days where packages are messed up. I don't think you can avoid malware by picking one over the other.
beardyw 9/9/2025||
>Makes me not want to use the ecosystem

I came to that conclusion long ago.

clbrmbr 9/9/2025||
Is it typical in the JS space to include dependencies without versioning?

Also, curious: does freezing a version really provide much protection? Shouldn’t a commit hash be used? (Attacker can change a tag.)

naugtur 9/9/2025||
packages published to npm are immutable. if you pin a version, you get the same exact version as long as MSFT servers are not compromised.

Installing from git is not recommended and has more issues than you might think https://dev.to/naugtur/a-phish-on-a-fork-no-chips-52cc

You are supposed to update packages, even if you use lockfiles (very common) or tools that pin your direct dependencies (renovate etc. not so common) And when you do update, will you read the package and all of its updated dependencies?

It's a hard problem with a bunch of tradeoffs.

Can be done, with enough attention and tools. Tools include LavaMoat :)

whilenot-dev 9/9/2025|||
> packages published to npm are immutable.

Depends how you'd refer to them... tags ("@latest", "@next" etc.) are not immutable and it's best to rely on the checksums in the lock file.

clbrmbr 9/9/2025|||
Re: updates: I was just thinking of waiting a few weeks on the updates to allow compromised packages to be discovered.
naugtur 9/9/2025||
socket.dev will find most malware within hours of it being published.

with LavaMoat most malware won't work even if you don't detect it.

vel0city 9/9/2025||
The package-lock.json includes a hash of the package, not just a version number which should be immutable.
whilenot-dev 9/9/2025||
To add to this: the hash in the lock file is the checksum of the published tarball, not the commit hash.
cluckindan 9/9/2025||
And then someone runs `npm install` on their CI
k4rnaj1k 9/9/2025||
[dead]
AtNightWeCode 9/9/2025|
I think JS should be all source and no packages at all.
phil294 9/9/2025|
What about complex SPAs? Database drivers? Polyfills? TypeScript?
AtNightWeCode 9/10/2025||
Pulling the source and compiling the package instead of pulling the package. Not much difference. Maybe slower build times but more secure and better builds.