Comment by jofzar
2 hours ago
'No Way to Prevent This,' Says Only package manager Where This Regularly Happens
Edit: some people don't understand that it's a defence to https://en.wikipedia.org/wiki/%27No_Way_to_Prevent_This,%27_...
2 hours ago
'No Way to Prevent This,' Says Only package manager Where This Regularly Happens
Edit: some people don't understand that it's a defence to https://en.wikipedia.org/wiki/%27No_Way_to_Prevent_This,%27_...
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.
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.
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.
> 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.
This however is only to some degree the package manager's fault. The JavaScript culture is strongly ordering tiny packages by individual people doing small things (left pad) rather than larger utilit libraries maintained by a larger community.
A larger community contributing to a larger library would mean that a larger community feels responsible and checks it.
That small package mentality a trace to web usage: JavaScirpt code is often sent to the client, not having a huge library but having small dedicated libraries means that it is a lot simpler for the bundler to not bundle dead code which is sent to the browser client.
With server side Node.js this lead to tons of dependencies ... which is worsened by npm allowing to have multiple versions of the same package in parallel. So if something depends on leftpad 1.0 and something else in leftpad 1.1 both are fetched and both are available.
3 replies →
How large a project do you typically use dotnet for?
IME dotnet dependency situation is a tire fire, not a month goes by without another dependency biting the dust or going fully commercial with no notice. Which is fair, I suppose, but Go and Java ecosystems don't have it nearly as bad.
3 replies →
> 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?
The package might not ever be executed on the user's machine. Depending on your setup, it might only be ran on a server, where the data that can be exfiltrated is completely different.
3 replies →
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.
One hour ago, while looking casually at a package.json, I saw this and was horrified:
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.
To meekly defend the indefensible here: it's not like rmdir on Linux (I won't speak for all Unixen) can cause loss of data, since it only removes empty directories.
Yikes. I would never approve a PR with that in it.
I hope the "standard" part is as much of a hallucination as "clever" is
> 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.
Claude probably birthed this abomination in the first place
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...
>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.
If I can - I avoid NPM completely and just go with no-build projects.
> 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.
And even in the ones that don't, having to wait until the project executes to begin its attack is a minor inconvenience for malware.
What other package managers do this? I don’t think Ruby does
4 replies →
You're right. I said the same thing and got downvoted too. Don't let it discourage you.
> 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
Wait how is being late worse than not doing it at all? Is it true for mortgage payments and apologies?
1 reply →
Mosts packages manager, allow that.
pnpm can still be exposed, afterall the worm simply have to wait you run tests locally.
You can isolate it through bubblewrap; I moaned about it here and there's no point in repeating it:
https://news.ycombinator.com/item?id=45041798
If you only ever use js/ts for frontend projects (like we do), it closes one major hole that I'm aware of, which still leaves at least two:
- the editor possibly starting random binaries from inside the mode_modules (such as biome, vitest, tsgo)
- escape from sandbox by using some kernel vulnerability, of which there have been many recently
I suppose.
But that's a "Perfect is the enemy of good"-like argument. Wherein: Why even reduce an easy to exploit attack surface when there could be holes elsewhere?! Because, you know, it makes things much more secure even if imperfect.
Plus, to me, it is a culture issue. npm just doesn't take security seriously, so we don't see these improvements, and if there was additional test hardening later, I don't expect we'd see them in npm either. Since, they just don't care.
3 replies →
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.
MS Nuget is also lock-by-default. Latest-by-default should be considered harmful unless the package manager is directly vouching for the veracity and reputability of the packages.
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.
[delayed]
So does dpkg & rpm
> 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?
There are so, so many things that NPM could do.
It could require a 48 hour cooldown period on any package update that wants to add an install script that didn't have one before, and has a certain number of downloads. And it could publish the list of these so security researchers have an opportunity to scan them.
It could add an optional key to package.json that allows someone to whitelist which packages can run install scripts.
It could add a Hardened Security program where (1) package maintainers could opt into a program where multi-factor confirmation by maintainers is required on every publish, even those triggered by CI; (2) this hardened package status would be public, and (3) a developer could set a flag in their package.json that causes any npm action to act as if all non-hardened packages had frozen versions.
And so much more.
2 replies →
> 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.
That's why we don't let the developers run system package manager install scripts as root. We do let them run npm inside containers, which is still more access than I'd like them to have.
Most package managers with postinstall scripts are also heavily curated and have reputation systems. As you say, they run as root, so the high trust requirement is definitely warranted. Anyone can upload an npm package.
1 reply →
I think it’s just a bundle of issues. Deep graph of dependencies, distribution of minimized code (java has jars, but I don’t remember scripts), and nearly impossible to audit. With most projects in other ecosytems, you only have to interact with a few developer/orgs. But with npm, you add one library and you need to essentially trust 10s of entities on the internet.
Nearly every package manager I've ever used had post-install scripts.
You're collapsing two different threat models. The risk isn't that code runs, it's WHEN it runs. This worm spreads because npm install runs arbitrary scripts as you, automatically, just from resolving the tree. You don't have to build it, run it, or even import it. Opening the project in an IDE is enough. apt/dnf scripts run on packages a maintainer signed and a distro gatekept. Not on whatever some rando pushed to a public scope 20 minutes ago that landed in your lockfile six levels deep. "They both technically execute code" is true and beside the point. One runs signed code from a trusted path, the other runs unsigned code from the default automated path. That's the whole ballgame.
4 replies →
The big attacks of today are spread across several package ecosystems: TrapDoor and Shai-Hulud have been hitting npm, pypi, composer, and crates with the same malware.
And all of them "thought" of security as an after-after-after-after-after-thought.
Most of these are now building upon techniques that have already been exploited since past 1 years. This attack used 4 of those techniques.
1. Lifecycle Hook Execution
2. CI/CD Identity Plane Attacks
3. Maintainer Account Takeover and Malicious Publish
4. Self-Replicating npm Worms
https://npm-supply-chain-attack-techniques.pagey.site/
2 replies →
People make this joke often. It's package managers and how loose we are with installing them, not NPM.
Cargo,PyPi,Nuget,PHP has had these recent too.
It's not just only NPM. It's frequently repeated here just cause of the average bias against Node.
But this problem isn't isolated to NPM.
The problem is compounded with NPM though thanks to lifecycle scripts: yes, any and all package managers create a risk of supply-chain attack, but NPM makes it dangerous to merely open a project up in an IDE.
> but NPM makes it dangerous to merely open a project up in an IDE.
It does not. Opening a project in an IDE has always been dangerous because there are about a thousand language server and analysis tools that run in the background. This is why IDEs ask you whether you trust the contents of a repository.
An even if some automated background execution initiated by the IDE doesn't get you, running `npm run test` 15 seconds later will.
It is the same for Crates.io and PyPI they also supply scripts without asking the user so opening an IDE will run them. For PyPI you need to even execute scripts to discover the dependencies!
That's a good point. For me it's getting people to realize they need to take up practice that help minimize these things. It's kinda us and them problem.
We need to ensure we don't just blindly install the latest, patch every CVE by just bumping everything to the latest even if the vulnerability has nothing to do with their system or use of said library.
We should have rules that we install the latest that's older than three days.
We should be running "npm audit" and other stuff like Trivy.
The three day rule alone could save most people.
nuget have targets, and allow to run code on build, it doesn't have this problem because there is less dependencies.
Pip, Composer, RubyGems, NuGet, and several others have lifecycle scripts.
As of course do the OS managers -- apt, yum, Homebrew.
> It's frequently repeated here just cause of the average bias against Node.
It’s frequently repeated here because NPM is where it keeps happening over and over and over and over and over and over again.
How many package managers allow executing arbitrary code as part of the installation process by default?
In short, the problem is `npm` not NPM.
Npm developers can relate to Windows being a target because it’s the most popular package manager.
Why would you target xyz pkg niche manager knowing that only 200 people will install them?
NPM does perform active offline & online vuln scanning on the packages. Everyone can do more, but they are going to be the #1 target.
Last 30 days:
PyPI, May 11. [1]
Crates.io, May 22 [2]
Composer, May 22 [3]
[1] https://www.tenable.com/blog/mini-shai-hulud-frequently-aske...
[2] https://socket.dev/blog/trapdoor-crypto-stealer-npm-pypi-cra...
[3] https://phoenix.security/laravel-lang-composer-supply-chain-...
All programming language package managers are vulnerable. They all have the exact same caveats as the Arch Linux User Repository. There are no trusted maintainers taking responsibility for things. Any random person can make an account and push packages.
IIRC, go cannot run arbitrary code at build time, so that should not make it vulnerable
That changes nothing. If you're downloading packages pushed by randoms, then it's vulnerable. There is no escaping it. Go's module index is filled with people's GitHub repositories. You have no idea what's inside those things unless you review the source yourself.
It's far far harder to do something exploits like this in elm because effects are tagged. There are solutions out there.
I think this is a thought-terminating cliche, and false equivalences. Stating "This area where problems occur at a high rate is not a problem, as problems can happen elsewhere too" is a curt dismissal of a valid concern. It implies the course of action, rather than to address a high-problem area, is to ignore any solutions which aren't global, or equate it to lower-incidence areas.
You bring up a good point that this class of problem, or related ones can occur with other package managers. It was frustrating how long it took the Crates.io team (Rust manager) to address name squatting, in what appeared to be a "no perfect solution exists, so we won't act" line of reasoning.
It was a reply to "only package manager where this regularly happens". Anyone who thinks it can't happen to them just because they're writing Python instead of Javascript is in for a world of hurt.
The comment I replied to is a literal meme. That's as charitable as it gets. Nothing "thought-terminating" about it.
It's the exact same logic people used for Apple computers back in the day. The idea that Macs didn't get viruses because they were inherently more secure. But that wasn't true. It was purely a numbers game. Windows' popularity was so far off the charts that hackers naturally targeted Windows users instead of Mac users; it was just a better use of their time. The same thing is happening here. Other package managers do get compromised, but the sheer frequency of npm incidents just reflects how overwhelmingly popular Node.js and web apps are right now. JavaScript simply has a much higher usage rate than most other languages.
Eh, it's worse than that. The GP comment is repeating a joke derived from an Onion headline about gun control. Where the very poignant message is about political will to make change. However, the npm ecosystem is very much willing and has already made several changes. If we're going to engage in discussion instead of meme-posting, the GP should have (imo) included real commentary _in addition to_ the meme they really wanted to post. What is the policy they want? Why do they see the NPM ecosystem as still resistant to change?
One easy change would be that before any package can be published, it has to wait a minimum of two weeks in a state where it can be reviewed but it can't be installed without jumping through several hoops with big warning signs, things like "INSTALL_INTENTIONALLY_DANGEROUS_PACKAGES_THAT_WILL_BREAK_MY_COMPUTER=1", selecting yes in a dialogue that asks if they want to install software that likely has viruses, and pointing to a different package repository URL.
If there's some change that must get out sooner, then there can be some fee to pay to npm to have their security team do their own review.
Critically, there must be time for someone to review before it's the default to be selected.
I'm sure there are issues with this, this was off my head, but it seems like a really easy step to at least stem the problem for now. And there are a bunch of ideas like this that would help, but NPM doesn't seem willing to take it seriously as an existential threat to the ecosystem, rather than taking trivial steps.
1 reply →
They didn't back up their meme with real commentary because they have no real commentary to stand on:
They're spreading cheap disdain & scorn for npm ("only package manager" framing). But most other package management systems have similar abilities to run pretty un-sandboxed code.
TrapDoor has hit python, rust, and js repos. https://socket.dev/blog/trapdoor-crypto-stealer-npm-pypi-cra...
Nix enters the room.
(Everyone claps.)
While true, tarring Arch here is a little unfair. AUR isn't enabled by default. It can't even be used via the same package front end, and in fact the "official" usage model requires that you clone the source yourself.
Indeed, AUR is bad as a software distribution mechanism (really it's best understood as a proving ground for baby packages before they get real maintainers and distro blessing), but it's less bad than NPM which puts the malware in the trusted/default/automated path.
I'm not tarring Arch, I was praising it. I made sure to explicitly spell out the "User Repository". Arch is the one that does it right.
I didn’t take it that way at all - rather, Arch is the only one that does it “right” with the AUR.
2 replies →
PyPI and Cargo are, 100%, vulnerable to this same class of compromises. That NPM sucks isn't a statement that everyone else doesn't.
There’s actually a blog post with that exact title.
https://news.ycombinator.com/item?id=48155690
tbf this is happening with a lot of package managers now, including pypi and composer
I've deleted and am rewriting this, to be more explicit, because HN downmodded the first comment to hell but I know I'm right and the crowd is wrong.
So, explicitly:
- pip
- Cargo
- apt/dpkg
- dnf/yum
- Homebrew
- RubyGems
- Composer (limited)
- Maven
...all allow scripts.
We understand the reference, it's just not correct: most package managers allow scripts, npm is the most successful package manager.
npm shouldn't allow scripts, but exploits happen everywhere.
Are scripts even necessary? I don't think e.g. mvn has any form of scripts¹, but if the dependency is compromised, you're likely to execute whatever compromised code is in there the next time you do mvn verify (or whatever). Slightly less wormable maybe, running tests or at least checking whether your thing still runs after upgrading package versions is really common, no?
¹ Annotation processors are a thing and somewhat similar to rust macros in function, but you need to set those up manually for each dependency, iirc.
If DNF/RPM is used there will often be a separate distro maintainer that should ideally review any changes coming from the upstream before pulling them into the distribution.
Also not all maintainers always pull in the latest upstream changes, only rebasing to new stable release or when the new features or fixes are actually needed for the distro stack.
Definitely not bulletproof but still IMHO more robust than "Lets just spray latest code from upstream without any review directly to production with a firehose!" that seems to be the norm.
Yeah with RPM and dpkg you're trusting the distro, or maybe individual distro maintainers, depending on how you consider it. But there are norms in the distro about what those scripts are for and how to use them, and there's some social enforcement around that.
The real issue for hooks in packaging formats like those is when you start adding third-party vendor repositories, e.g., Zoom, Google Chrome, Discord. None of the social enforcement mechanisms are there and the companies behind the products I just mentioned all have histories of abusing them.
That's why it's generally better to use Flatpak for things like that if your distro itself doesn't include them.
1 reply →
Yes and typically updates take a while to be deployed...
Maven does not run arbitrary scripts just by including a dependency.
It's not the package manager, it's the repo and the cryptographic signatures that are trusted by the package manager and the users who choose to point their pacakge managers at those repos. The fundamental problem here is that people's risk assessment is treating a user named devioustiger12345 as having the same situation and story as Microsoft/Apple/Red Hat.
> HN downmodded the first comment to hell but I know I'm right and the crowd is wrong.
Got downvoted for saying it too. Don't let it discourage you.
Please stop posting this on every single security incident thread with npm. It was funny once, it's just rehashing the same debate over and over.
On the other hand, if the same problem keeps happening, it's hard to argue that the problem isn't foundational to the design and that it should be called out until either the problem is fixed or the design abandoned.
Why should they stop? Maybe they want to rehash the issue that's not being adequately addressed. Maybe it's not supposed to be funny.
How do you propose we address this issue? Instead of policing what people say, are you interested in sharing your or someone else ideas?
It's not that there isn't a conversation to be had. It's that it's a low-effort, karma farming, reddit-tier comment that always invites emotional/reactionary responses, typically the same ones as before, that usually shoots to the top of the comments section and drowns out any relevant or interesting (see: curious, as per HN guidelines) discussion.
1 reply →
Opponents of gun control surely feel the same way about the Onion’s story.