Let me provide context, since a bunch of people responding with "every package manager can be hit!!!" npm, by design, allows all packages to run package supplied arbitrary code as the logged-in user after an update completes.
That's an INSANE default. pnpm, by contrast, allows you to essentially "opt-in" only specific packages that need this (e.g. four out of thirty, in one of our projects). Then tacks on tons of other security settings, like minimum age, no trust downgrade, etc etc.
All attackers can attack packages by updating how a package functions; but npm is particularly problematic as it runs non-sandbox scripts as the calling user. Putting not just your project at risk, but your entire machine/network.
And this stuff has been known about for YEARS, they've taken no action.
> allows all packages to run package supplied arbitrary code as the logged-in user after an update completes
As opposed to the completely untrusted package supplied arbitrary code that the logged in user executes when they actually use the package immediately after installing it?
Yes, this.
Regarding npm CLIENTS, PNPM is fundamentally different from (and superior to) npm or yarn.
Strongest possible recommendation to use pnpm.
It's also a good idea to use a private registry (eg via jfrog), acting as a proxy / pull-through cache, and point trad SAST and maybe AI scanners at it.
But dropping the npm client in favor of pnpm is a no-brainer. Speed, disk space, security, determinism, flexibility, fine-grained control over your dependency graph...
One hour ago, while looking casually at a package.json, I saw this and was horrified:
rm -rf pkg/snippets & rmdir pkg\\snippets /s /q & wasm-pack build --target bundler && node prepare-web.js
Looked like a strange mix of unix shell and msdos batch that would, on my box, try to rmdir "/s" and "/q". I asked Claude about this, and he replied something like "Yes that's a standard and clever hack to delete a directory that works both on linux and windows!".Poor Claude has been trained on so much awful human code that it required several prompts for it to admit that there was indeed a problem.
The industry is the process by which convenient crap like this gets standardized.
>Putting not just your project at risk, but your entire machine/network.
Between average hackers and extortion groups, foreign governments and state sponsored actors and last but not least my own government, I don't think there's much room left for non-compromised supply chains these days. Treat everything that can run foreign code as potentially compromized and keep everything compartmentalized. If you keep your crypto wallets or private banking info on the same machine where you do development, you're asking to get shafted one day. Or if you keep your big corporate github keys on the same machine where you do private weekend projects. It doesn't matter what you use in particular, even if some vectors are currently more popular than others.
> That's an INSANE default.
I agree that not running arbitrary installation scripts is the right default, but it's just an incremental improvement.
The practical difference between code that runs at installation and code that runs when the package is executed is, very typically, a small amount of time.
IMO, the hyperbole here hurts because it distracts from more effective efforts.
> since a bunch of people responding with "every package manager can be hit!!!" npm, by design, allows all packages to run package supplied arbitrary code as the logged-in user after an update completes.
This is semi-common and in no way unique to NPM.
They have taken action as of very recently. The latest version [1] of npm warns when there are install scripts and tells you they will be disabled by default in a future version, with a per-dependency opt in mechanism [2].
> they've taken no action.
Not running lifecycle scripts by default is eventually going to be the default behavior. Late is worse (edit: I meant better) than not at all. https://github.com/npm/rfcs/pull/868
Mosts packages manager, allow that.
pnpm can still be exposed, afterall the worm simply have to wait you run tests locally.
npm is so bad at everything it's insane.
SIXTEEN YEARS of development and they can't even resolve a tree of dependencies in the correct manner unless you nuke the lockfile and node_modules.
Dependency resolution is literally the number one task and they fail at it. How can you expect them to be good at anything else? Absolute joke.
Maybe NPM is scared to break a ton of packages? I also think action from NPM on the repo level is vital
I went through the package.json on my machine - seems like ~400 / 60000 or 0.7% have (pre|post)install. (That's not all of the scripts that run at install)
Seems to me like a backwards compatibility is a non argument since pnpm is popular enough to stand as existence proof that scripts can be, at least, opt-in
IMO - pre- and post- install scripts should just be abolished/deprecated. It should require a special dispensation from npm to even publish one. A better system for binaries (needed by esbuild) is probably needed.
Even saying "just use pnpm" isn't enough, we need to get the developer community to herd immunity and that isn't going to happen on an opt-in basis.
I would love for npm to sandbox as well. But I think the better way forward is just turn off scripts.
So do the pre- and post-install scripts of Debian packages. The problem is not this but the lack of verified and controlled release channel.
I think another thing that affects security is that in javascript culture people often tie to the latest version instead of concrete version.
This makes it so an update to a popular library can compromise a huge number of packages that depend on it.
In Java for example almost all packages specify a concrete version, even if someone compromises the latest the blast radius is usually pretty small.
> That's an INSANE default.
It's also the standard, and by far it's the contrast to not allow this. pnpm has a massive advantage of being the non-standard package manager, npm does not have that - what do you suggest that npm does?
i've been thinking about this as well. but having built a startup, i've learned that users don't care as long as they are given the value and most convenience. they don't really care much at security as much as we do. just look at openclaw? but maybe it's our job to make sure it is taken care of vs assuming the user cares and just make it look seamless.
Every package manager, by design, allows arbitrary code execution after the update completes. It is the entire purpose of a package manager. There is no point installing code that does not run.
> Let me provide context, since a bunch of people responding with "every package manager can be hit!!!" npm, by design, allows all packages to run package supplied arbitrary code as the logged-in user after an update completes.
Many package formats before NPM allowed for it, and frankly, it matters little, because if it can add code to your app it can run malicious code. The fact it executes on package install rather than when dev runs tests or the app matters little, and in general if environment is sandboxes, the package install is also ran in the same sandbox so disallowing it changes little.
so yes, every package manager can be hit, the reason is twofold
* JS is such a lowest common denominator it has that much more clueless users so just by scale every issue will be more common than in other languages
* extreme fragmentation leading to hundreds of packages needed for even small projects, which is again more chances for compromise
[dead]
Nearly every package manager I've ever used had post-install scripts. Most run as root, since that's what usually what the package manager runs as.
It's not unreasonable: you're already installing software, which presents risks. If post-install scripts were not a thing, a payload could still run because you ran the software you installed. Or because the installer added it to auto-run. Or because the installer placed it somewhere where it would be dynamically loaded all the time.
Furthering the idea that not all package managers are the same, there are entire cycles of the moon where I don't open nuget once. Some ecosystems simply don't need to vendor out very often, and these are the ones where you generally find the least news like this.
In about 99% of cases, I have the option to pick between Microsoft, a 3rd party or myself. I'm picking that first option every time I can. If M$ can't handle it, I'm hand rolling it.
Dapper remains the only constant 3rd party dependency in my projects. I don't know how much longer this will last with LLM assistance. The frontier models are very good at writing repositories over arbitrary sql schemas with low level primitives now.