4 ms·
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 supplie
by Someone1234 4mo ago
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.
- dns_snek 4mo ago> 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.
- Ajedi32 4mo agoAnd even in the ones that don't, having to wait until the project executes to begin its attack is a minor inconvenience for malware.
- an0malous 4mo agoWhat other package managers do this? I don’t think Ruby does
- matheusmoreira 4mo agohttps://docs.ruby-lang.org/en//master/Gem.html#method-c-post_install https://docs.ruby-lang.org/en//master/Gem.html#method-c-post...
- IshKebab 4mo agoPython does too I believe. Really the reason not to allow that is for robustness, not security. You ideally don't want package installs doing random stuff to your system because package authors are generally bad at doing that sort of thing cleanly. The security impact is relatively minimal because as other people have said, you just installed a package. What's the very next thing you're going to do? Compile/run it obviously.
- oblio 4mo agoA lot of packages are pulled in to call minimal bits of the actual library. I obviously don't have any statistics on this but my instinct would say that for the average application only 5% of an average package is actually used. So not running package installation scripts is a huge, massive problem.
- IshKebab 4mo agoSo what? Packages can just put their backdoors in some initialisation code that is always used. It is possible that not running package installation scripts could improve security, but for that you need really good sandboxing/compartmentalisation of library code, e.g. with CHERI, WASI component model, or if all of your code must run in a secure context it probably helps. But those situations are unfortunately rare in my experience.
- dns_snek 4mo agoIt doesn't matter how much of the package you use. Here, you can use literally 0% of Koa and get pwned by one of its transitive dependencies (koa > cookies > keygrip > tsscmp) by simply importing the parent package: mkdir demo && cd demo npm install --save koa@3.2.0 echo 'console.log("--- pwned by a transitive dependency ---")' >> node_modules/tsscmp/lib/index.js node -e "import 'koa'" --- pwned by a transitive dependency ---
- oblio 4mo agoMy point was for proper package management tools that don't allow running scripts.
- dns_snek 4mo agoMost of them? Ruby gems have hooks, Python has setup.py, deb, rpm have them too (relevant if you're installing from 3rd party sources). Elixir/Mix doesn't technically execute code on install, but your language server builds the dependencies as soon as you open the project, which can execute arbitrary code. Either way it misses the point, nobody just fetches code and removing post-install scripts wouldn't change much because you're going to run `npm run something` 5 seconds after you run `npm install`.
- matheusmoreira 4mo agoYou're right. I said the same thing and got downvoted too. Don't let it discourage you.
- sigmoid10 4mo ago>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.
- renegade-otter 4mo agoIf I can - I avoid NPM completely and just go with no-build projects.
- bob1029 4mo agoFurthering 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.
- johannes1234321 4mo ago> 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.
- homebrewer 4mo agoThis has been improving recently; one large project built on several heavy libraries that I've been supporting since 2018 currently installs ~180 dependencies without loss of functionality compared to how it worked, and what it depended on, back in 2018. IIRC 6 years ago the full dependency tree congealed into more than 2000 packages. One small example is React itself: - 5 deps: https://www.npmjs.com/package/react/v/15.6.2 https://www.npmjs.com/package/react/v/15.6.2 - 0 deps: https://www.npmjs.com/package/react/v/19.2.6 https://www.npmjs.com/package/react/v/19.2.6 Another is switching from create-react-app with its hundreds of transitive dependencies to vite, which, according to the test I've ran just now, currently has 15. Etc.
- Kuinox 4mo agoMosts packages manager, allow that. pnpm can still be exposed, afterall the worm simply have to wait you run tests locally.
- Someone1234 4mo agoI 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.
- Kuinox 4mo agoThe biggest problem is not software but culture, not at npm, but in the js ecosystem. The js ecosystem is simply a juicy targets, the attack surface is enormous. The attacker can make their attack more sophisticated, there will always be a maintainer that can seed the worm spread. Meanwhile in the nuget ecosystem is way smaller and have way less mainteners involved for a single given dependency.
- lenerdenator 4mo agoI'd go further and say that how JS and the web itself has been run over the years has predisposed it to this sort of thing. JS didn't have a passable stdlib until ES6. It had bugs built into it because Eich was given a stupidly short time window to deliver the first version. Everyone (particularly MS) had (and still sort of do) their own way of interpreting the language. In spite of all of this it became the primary way of developing applications for public consumption. This led to a bunch of people who wanted to be the 10x JS engineer to solve problems with their own libraries and technologies. None of them really talked, they just threw their packages on NPM's registry without second thought and some gained widespread use just by accident. Google tried fixing some of this with Dart but chickened out at the last second. TypeScript was designed by someone competent but can't fix the larger cultural issues. This is what happens when you put SV hubris and "moving fast and breaking things" over doing things the right way.
- ImPostingOnHN 4mo agoNearly 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.
- TylerE 4mo agoNearly 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.
- ImPostingOnHN 4mo ago> You're collapsing two different threat models. The risk isn't that code runs, it's WHEN it runs. > You don't have to build it, run it, or even import it If you just installed something with npm, chances are you'll be running it shortly, either as a tool or a library, probably minutes or seconds later. I imagine the use case of installing an npm package you don't plan on using or transitively importing, constitute a small portion of npm installs.
- ChocolateGod 4mo ago> apt/dnf scripts run on packages a maintainer signed and a distro gatekept Unfortunately apt/dnf isn't much better here because random tutorials online suggest people add random repositories where the creator of any repository effectively has root access to anyone machine that adds it as a remote.
- semiquaver 4mo ago> 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 https://github.com/npm/rfcs/pull/868
- brookst 4mo agoWait how is being late worse than not doing it at all? Is it true for mortgage payments and apologies?
- deleted 4mo ago[deleted]
- insanitybit 4mo ago> 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?
- btown 4mo agoThere 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.
- insanitybit 4mo agoYou realize that "dependency cooldowns" as a popular concept are extremely new, right? npm manages the installation of dependencies for millions upon millions of users across the globe. > 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; Great, they did this. > And so much more. This shit takes time. Yes, they should have done this on day 1. Acting like any of this is easy to retrofit is just nuts though.
- j1elo 4mo agoWhat is being said is that a new flag like '--minimum-release-age' would take, realistically speaking, tops 4 hours to implement (without AI assistance), plus a good 1 week of thorough testing, and maybe a 1 month period of progressive deployment. Come on, let's give it a total of 1.5 months, for good measure. Of course this should have been started since the beginning of the major recent stream of supply chain attacks, circa 2024 or 2025... but even assuming the most backwards calendaring possible -starting after the last bug compromise (Axios, on March 31st)- that new flag should have already been shipped a couple weeks ago. Shit does take time, but where there's a will there's a way, and nobody buys that this shit would take that much time.
- chrisweekly 4mo agoYes, 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...
- matheusmoreira 4mo ago> 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?
- saturn_vk 4mo agoThe 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.
- Petersipoi 4mo agoSure but like.. come on. Is that really a defense? Most packages are run on devs machines. And it's not like "Oh it's just running on my production server, what could go wrong there" is any better.
- ZiiS 4mo agoWe should not dismiss that it is slightly better. Production servers vary rarely have creds to the source repository nor to other production servers running possibly more sensitive code where investing in a smaller supply chain was justified.
- PunchyHamster 4mo agoWhy you are downloading code if you're not even using it to run tests ? And if you run tests in CI/CD, or in a container, why you are downloading code locally ? Only thing that comes to mind is code completion but surely most people at least run unit tests locally before pushing the code out ?
- Sankozi 4mo agoOne malicious script that is run right after install vs one per each API entry point that might be called or not (transitive dependency).
- Romario77 4mo agoI 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.
- Pxtl 4mo agoMS 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.
- Uvix 4mo agoNuGet is lock-by-default for the parent package, but with the move from packages.config to <PackageReference> it's no longer lock-by-default for dependencies.
- Pxtl 4mo agoIt never made sense the other way. If I reference a package, logically I'm also referencing its dependencies at the version that the package uses. Forcing the user to also reference dependencies of dependencies of dependencies means the package reference lists aren't DRY.
- Uvix 4mo agoBut just the dependency list isn't sufficient to pick a specific version, thanks to dependency ranges. If Package A depends on Package B >= 1.0, and Package B has v1.0 and v1.1 available, it will use v1.0. But if Package B suddenly unlists v1.0, then future restores will change to v1.1.
- Pxtl 4mo agoAh, I see the worry. A supply-chain attacker can use de-listing to force an upgrade to the malicious version if clients have dependency ranges that reach into the future. I didn't know about that one. In general, any dependency system that allows "you can silently upgrade to versions of the package that did not exist at the time the packagereference list was created" seems to be a vulnerability. It's frustrating since this vuln seems trivially simple to fix, at a glance... although it would require an API change in PackageReference. Mandatory lockfiles by default, or getting rid of the floating versions misfeature. BindingRedirects let you override declared dependency versions anyways, they're not a blood pact.
- westoque 4mo agoi'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.
- dijksterhuis 4mo agousers don’t care about security until it goes wrong. then they will be angry. security is a hidden requirement.
- rixed 4mo agoOne 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.
- lokar 4mo agoYikes. I would never approve a PR with that in it.
- lionkor 4mo agoYour agent might!
- PunchyHamster 4mo ago> 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
- cozzyd 4mo agoI hope the "standard" part is as much of a hallucination as "clever" is
- tremon 4mo agoTo 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.
- MattSteelblade 4mo agoIn this case, the rm -rf before that does. The rmdir is the Windows command in this example and with /s /q, it will quietly delete everything.
- Talpur1 4mo ago[dead]
- PunchyHamster 4mo ago> 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
- tonymet 4mo agoSo does dpkg & rpm
- tln 4mo agoMaybe 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.
- pajko 4mo agoSo do the pre- and post-install scripts of Debian packages. The problem is not this but the lack of verified and controlled release channel.
- jmull 4mo ago> 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.
- Someone1234 4mo ago> IMO, the hyperbole here hurts because it distracts from more effective efforts. For example?
- megous 4mo agoCan I just run npm update diff and see all changes across all updates compared to the last reviewed code in node_modules? Why not?
- halapro 4mo agonpm 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.
- bakkoting 4mo agoThey 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]. [1] https://github.com/npm/cli/releases/tag/v11.16.0 https://github.com/npm/cli/releases/tag/v11.16.0 [2] https://github.com/npm/rfcs/pull/868 https://github.com/npm/rfcs/pull/868
- hedora 4mo agoThis is way too little, way too late. To see what I mean, try actually packaging a cross-platform binary dependency in their ecosystem.
- bakkoting 4mo agoI have; you specify one optional dependency per platform and set the requirements in each package. It works fine. A bunch of packages do this (e.g. esbuild). I don't know what your complaint is or what you're asking for.
- tardedmeme 4mo agoEvery 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.