FR version is available. Content is displayed in original English for accuracy.
Advertisement
Advertisement
⚡ Community Insights
Discussion Sentiment
56% Positive
Analyzed from 9858 words in the discussion.
Trending Topics
#npm#package#security#packages#https#code#docker#more#should#run

Discussion (300 Comments)Read Original on HackerNews
It's a convenience feature that provides built-in Arbitrary Code Execution (even for transient dependencies), and every one of these widespread NPM worm style attacks has propagated through it, because of the default setting. Also enabling it for one command shouldn't automatically permit all transient dependencies to run lifecycle scripts, it should be required to explicitly mark each dependency to limit it to where it's absolutely necessary.
The vast majority of NPM packages do not depend on these scripts, and you should disable them globally if you haven't already.
This default can affect all consumers of NPM packages, regardless of whether you use yarn, pnpm or npm itself, because most package maintainers use NPM. This is why it's NPM's responsibility to change this default in order to prevent spread of malware in packages.
That said, packages could still just run whatever junk they want when they first get imported in a program.
There's not a word in the English language that really expresses how absolutely stupid the npm ecosystem is and the developers that perpetuate it by importing a package rather than writing 5 lines of code.
Python packages traditionally use setup.py to install code, and setup.py is all executable code under the installed package's control.
Native Ruby Gems execute arbitrary code via extconf.rb.
Pre .NET Core, NuGet packages could ship scripts like `install.ps1`. That's been removed, but they can still ship `.targets` and `.props` files that are incorporated into your build (and so can run code at build time).
PHP Composer packages can ship install scripts or configure themselves as Composer plugins.
The venerable .tar.gz approach to packaging, covering decades of C and C++ code, is all about executing code during installation.
There are measures that can help (e.g., PHP Composer doesn't run install scripts of _transitive_ dependencies) but the JS space is adopting measures that can help too (like pnpm's approve-builds).
(For non Rustaceans: "Placing a file named build.rs in the root of a package will cause Cargo to compile that script and execute it just before building the package.")
1. Every day there's a new package.
2. Then five more packages appear so you don't have to write that one terrifying line of JavaScript yourself.
3. Then someone writes a wrapper around those five packages.
4. Then someone writes a "modern, lightweight, zero-config" wrapper around the wrapper.
5. Then a framework adopts it, a build tool requires it, and suddenly your todo app has a dependency graph that looks like international diplomacy.
6. Out of 100 devs building the same product, there are now 300 different dependency combinations, all somehow involving 'left-pad' spiritually if not literally.
7. Half the packages are maintained by one person, unpaid, at 2 a.m., after getting yelled at in GitHub issues.
8. The other half were abandoned three years ago but still have 40 million weekly downloads because removing them would break civilization.
9. Pinning dependencies sounds nice until the ecosystem tells you, "sorry, this package only works with Node 22, this plugin needs Node 18, and this transitive dependency has discovered ESM enlightenment."
10. So everyone lives on the bleeding edge, except nobody agrees where the edge is, and the bleeding part is very real.
So yeah, npm is not uniquely cursed because JavaScript devs are worse. It's cursed because it turned code reuse into a lifestyle, dependency trees into rainforests, and 'npm install' into an act of faith.
By a manager for for a >$1 billion market cap corporation who doesnt understand that the one person isnt an employee.
It certainly reads as LLM generated!
It's a sad state of affairs, for sure - but is there a reason we can't just switch our frontends to static BOMs, and trust that NPM at least gets their "you can't republish to an old version" bare-minimum constraint right?
But then the compliance team gets annoyed because some CVE with a CVSS score of 3.1 that has a patch available sits unfixed.
That would wake NPM up at least to the notion that it's absolutely reasonable to require OSS maintainers to press a button on their phones when releases go out, and that's a good thing not a bad thing.
They don’t want to pay engineers to do the analysis manually, and they don’t want to pay for someone to figure out a better automated system.
Would anyone be surprised at their car having problems if they cheaped out on oil changes?
... Does NPM not create full lockfiles, with hashes and pinned transitive dependencies and everything?
IMO this is built on a pre-ShaiHulud, pre-AI set of assumptions, and should be evaluated from first principles with today's security situation.
But even if the dev community comes up with super hardened security, I fear in at least a year the models will be good enough in social engineering that we are still running a losing game.
Never mind questions of how good the models will/can get. I'm confused why people expect that, in principle, models getting really good at social engineering would have such huge impact. Seems to me like it has diminishing returns and is severely bottlenecked by the fact that the target operates at human speed.
The amount of effort involved in the XZ hack, for example, was immense, and it couldn't have been accelerated because it worked specifically by wearing the existing maintainer down over time. You could generate and send all the necessary nastygrams in seconds and it wouldn't speed up the human consuming them (and in fact, having all of them arrive at once would raise suspicion).
And there is a limit to how persuasive that input can be. Take any of the random nastygrams directed at the XZ maintainer; maybe they could have been made more nasty, more pointed, more aware of the maintainer's personal weaknesses and fears — but would that have actually been overall more effective? I think not, or at most only a tiny bit.
https://markdownpastebin.com/?id=9c294c75f09349d2977a4ccd250...
(btw that the Titanic sunk is not an excuse not to secure other ships. And it did save a great many other ships to have watertight subdivision.)
So... Although there are exploits escaping containers and VMs and then bad guys doing lateral moves across machines, you still want defense in depth.
https://github.com/nrwl/nx-console/security/advisories/GHSA-...
PS: I posted on HN to try and alert people right after it was compromised but sadly got almost no upvotes :-(
I concur, the best part of working with Deno way back was its standard library [0] and overall complete dev environment. It is just so damn obvious that a runtime comes with an integrated test runner and assertion library.
0 - https://docs.deno.com/runtime/reference/std/
Of course, the trouble is that there are so many test runners in the Node ecosystem and many of them cannot be as easily replaced as Mocha, so the shift to the out-of-the-box test harness and assertion library will of course be painfully slow. People like the over-complicated nature of both Jest and Vitest for all sorts of reasons. Major companies thought Karma was a good idea. (I still don't understand why more developers didn't cringe at "Yo dog, I heard you like V8 for your unit tests, so we're gonna spin up a second, different copy of V8 from your existing V8 environment.")
[0] https://nodejs.org/api/test.html
[1] https://nodejs.org/api/assert.html#strict-assertion-mode
Do any language standard libraries have a "3 hours ago" formatter? Thats what timeago.js does
Maybe slice.js, which just does python-style indexing with negative numbers. TC39 already made array.at() and array.slice() handle negative numbers.
There's also a platform feature for that now: Intl.RelativeTimeFormat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It asks you to do the basic time math to determine your granularity so there's still a role for a library, but also that time math gets easier with Temporal: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
(Specifically `Temporal.Now.instant().since(somePastInstant)` returns a Temporal.Duration that you can relatively easily determine the highest granularity you want and pass that to an Intl.RelativeTimeFormat instance. Also Intl.DurationFormat which is what a Temporal.Duration's `toLocaleString()` uses may also be good enough in many "x hours ago" type situations, though it is over-precise for them.)
So, back to the GP post - TC39 should make a bigger stdlib.
Lets say timeago.js is warranted (as a polyfill and terser API) AND TC39 is taking action.
On slice.js, TC39 took action AND usage is unwarranted since the functionality is widely available. Maybe a stride.js would be needed.
There are 2 modules where npm's culture of "tiny modules because the stdlib is impoverished" holds - but the issue isn't TC39 really. There are 312 modules that aren't related to npm's culture of "tiny modules because the stdlib is impoverished".
https://nodejs.org/api/
> The payload checks for the Docker socket and, if present, attempts container escape through three sequential methods:
So even if you're running devcontainers / VMs, these worms are already trying to escape.
Make sure you're running a rootless VM engine (e.g. podman instead of docker) !
It reminds me of the good old days when people would hand out low privilege Linux accounts and rely on the kernel to prevent privilige escalation. Docker is literally the same thing, just with extra steps. Especially today with new kernel LPE'S dropping every 5 minutes.
Yes, Podman is a bit better because you arent handing the attacker root, but... why hand them an account at all? Just use a grown up VM.
Solaris Zones and FreeBSD Jails (their inspiration) also share a kernel with the running system and do not seem to have as many escape vulnerabilities.
(Though partly because there may not be as much scrutiny of course.)
Then I've been toying with using WASM, with a strictly limited API surface... (API stands for what, "Attack, Please, Infiltrators"?)
I'd really love to make a service which can run "untrusted" code... I want this to exist. I want it to feel like the Sandstorm.io marketplace, and to use Tailscale or something like it... and then to make "Facebook but only for friends or friends-of-friends." No public figures. No random people or ads in my feeds. Just friends. And then other similar apps - mail, discord, etc. Don't let it make outbound HTTP connections. Don't let it access local filesystem, other than assets that were bundled with it. Give it a SQLite API... And let it handle inbound HTTP, REST, WebSocket requests... And use gRPC over Tailscale to only talk directly to approved contacts...
Thoughts? How to run untrusted code safely?
I tried using Firecracker and gVisor... But I'm dissatisfied with them. I was trying to make it easy for someone to download and run my service... But Firecracker and gVisor don't at all feel like "libraries that install cleanly." They feel more like, if you're enterprise scale, you can hire someone to make sure Firecracker and gVisor work the way you want... Maybe I'm just not trying hard enough... Maybe using WSL2 on Windows 11 is just asking for trouble. I tried several different ways to run Linux on Windows, and none of them seemed very happy, when I tried to add Firecracker / gVisor.
The reason you don't use a "grown up VM" is because it's significantly more difficult. Which VM? Firecracker requires KVM and a guest operating system - so how are you getting things in and out in a way that doesn't violate security? That's real work.
gVisor is great and my recommendation, certainly, but the difference between "nothing" and "docker" is actually pretty huge imo.
You've got me there, but it's not really saying much.
Seccomp, for example, is nice, but... It blocks ~44 system calls, and leaves 300 plus exposed. Any memory corruption issue in those remaining calls remain wide open. So better than nothing? Absolutely, but it leads to a false sense of security. I know actual security researchers that intentionally run malware inside Docker and think they're safe. They're not.
Then we can talk about docker itself. It had something like 6 public CVE's related to full escapes last year. If your patch cycle takes 30 days then you spend about half the year with a full, public, escape known. Even if you patched those all on day one you spent most of the year vulnerable to one of the many Kernel vulns that it doesn't stop. On any given calendar day it's statistically likely there is at LEAST one way to escape publicly known and unpatched.
So, yeah. It beats nothing by a huge margin, but it's WORSE than nothing if you think it's safe to run arbitrary untrusted code in. That was never what it was for, it's just what people treat it as. It's not a VM, wasn't designed to be, and people need to stop pretending it is.
... Did that actually stop?
... Is that not the purpose of being able to make multiple accounts (even on a random desktop or laptop system) and restrict their privileges?
I wrote a comment ~8 years about this[1], I'm kinda sad people still do this and seem to misunderstand just how big of a security hole they are opening...
Just don't do it. If you absolutely must then you can configure some very restrictive AuthZ plugin (but those are incredibly fickle and are almost certainly security theatre because they are basically just an application firewall).
[1]: https://news.ycombinator.com/item?id=17983623
I'm not sure I agree/understand. If you've somehow bypassed AppArmor and cgroup mechanisms then any UID/GID remapping is irrelevant. At this point you're in a position to directly manage memory.
What do you mean by "kernel escape"?
Also, if the container has access to dbus, one can try to exploit multiple services listening on dbus.
Amazon has been doing it with Firecracker for a while and Kata containers is another popular one
https://github.com/firecracker-microvm/firecracker
https://github.com/kata-containers/kata-containers
https://github.com/matheusmoreira/virtdev
It's been working really well. Use it every day. Just make some machines and ssh in.
Extra 'overhead' and heaviness (perceived or real).
Aren't most people running docker rootless (at least on Linux)? Does podman do more?
"Rootless mode lets you run the Docker daemon and containers as a non-root user."
https://docs.docker.com/engine/security/rootless/
This is how docker is best installed on Linux, and there's a convenience script for it as well (https://get.docker.com/rootless). I am surprised that's not how people are using docker.
often, docker in docker is used to manage docker orchestration. putinng a user in a docker and peoviding docker access is security through obscurity.
on the flip side, i see people blindly installing tools and skills not understanding they are pushing context and capabilities without any significant security features.
Imagine mythos is actually exceptional hacker. if you give it a well crafted malicious prompt, its going to even more insecure.
the double edged sword is really fascinating to think about
In the HPC space Apptainer (previously "Singularity") was created precisely due to (multi-)user-level access, especially with the use of NFS.
On Debian derivatives, you need some kind of extra privs to even talk to it (being a member of the "docker" group, iirc).
> podman info --format '{{.Host.Security.Rootless}}'
to ensure podman is rootless in your config.
This seems analogous to how we tackle email spam and general malware. It means that there is almost always a target valuable enough for bad actors to continue trying. However, unlike email (mostly...), package managers are centralised authorities (and anything out-of-band is surely the developers problem?).
My ill-informed feeling is that we might need to change the culture of lazy versioning with rapid releases and focus on stable, deeply scanned versions at registries. There will be some effect of volume and scale so I could be off, but it still seems telling that this impacts high-churn languages more often.
I don't know, I would love a comprehensive article that explores the landscape right now.
The roller coaster in that movie was called Mr Bonestripper, https://www.youtube.com/watch?v=NEZEgd8GjJc .
Instead it comes from Roller Coaster Tycoon 2, https://knowyourmeme.com/memes/mr-bones-wild-ride .
As for the comparison with spam, there we kind of settled on making people accept spam by vacuuming up their email addresses in pretty much every commercial and social computer network setting, giving it a veneer of legitimacy. I think it is likely to happen in this area too, perhaps some combination of Oracle licensing surveillance agent style software and automated dependency management, i.e. 'solving' supply chain malware by whitelisting some other malware.
https://aube.en.dev/package-manager/jailed-builds.html
But this feels like a cat/mouse game.
1. It seems like the restrictions are only for lifecycle scripts, so wouldn't help if/when the package's actual code had malicious code inserted?
2. Package managers like pnpm seem to entirely block lifecycle scripts by default, so I guess this is an in-between solution.
Still, I guess it's a step in the right direction for those want or need to run lifecycle scripts specifically.
That is what made Bun popular, and tools like uv/pip, oxlint/eslint, orbstack/docker desktop, and the list goes on. Drop-in replacements where we get 10x with little effort.
https://npm-supply-chain-attacks-25-26.pagey.site/
But, it's a good feature to have.
Thanks.. gonna integrate now :)
The scroll seems to jump all over the place on my device.
In JVM-land, thanks to binary distribution being the default, the number of packages you can usurp to achieve the same compromise is fairly small; essentially Maven and Gradle plugins. Which is why you should be extremely wary when, say, Sentry tells you to add them as a dependency by setting up their Gradle plugin. Not sure about sbt. Clojure source dependencies can provide "prep" scripts, which are not automatically run as part of a build, but still execute code on your machine.
There's a pattern here: some build tools incorporate dependency-provided code as part of the consumer project's build, and that is a juicy attack surface. Packages which include such code, or are recently updated to include it, should be treated with extra scrutiny.
The trickier part is dev environments, but ideally you take a similar approach. The place that devs do `npm install` should be isolated from, say, your browser / ssh keys etc.
Package manager support would be an amazing win here since you'd have an easier time managing the isolation but you can do this today.
How does having an AI audit external code help? Can they not be prompt injected to ignore a malicious change?
I guess I am sort of concerned that they are a pretty thin layer and even if you put "DO NOT ALLOW PROMPT INJECTION", it's a bit like saying "make no mistakes". There _is_ a priority between `system` and `user` level messages as I had recalled, so a specifically made tool that has its own system prompt should prevent injection while asking Claude CLI could still allow for prompt injection.
What are your thoughts and experience?
The concern is real and unsolved. I think security researchers have an advantage here because they still can fall back to manual audits if their automated analysis (or scores thereof) is off.
My JS is frontend only, served as a compiled bundle off a server that doesn't even have a JS runtime of its own. Whatever random vulnerabilities the frontend contains are limited in blast radius to the user's own browser, and since all frontends should be untrusted anyway, there is no real security risk to the server or backend. No reason to update more than a few times a year, if that.
Combine with obvious basic security practices like pnpm cooldowns + no build scripts. When you upgrade a few times a year, and frontend vulns don't matter, there's really no limit to the cooldown you can set. 60 days, why not.
The standards haven't changed; for the vast majority of JS programmers, this is their first programming language and they have no solid foundation of architecture and security.
So what you get are these overly enthusiastic newbies that want to share their latest achievement with the world (say, a function to left pad a string), and why not include a fancy post-install script with emojis that makes adoption even simpler for other complete noobs? And this is the result.
You're not wrong that there's a lot of crap, a massive legacy, and some bad behavior. It is also approachable, flexible, and portable. Even if you sometimes need to say "Wat?!?"
Where does that compilation happen again? Not on the front end and it happens exactly where the exploits have been targeting (dev and build boxes).
Funnily enough, I don't actually think I do serve third party JS, though. Don't serve ads, don't use external telemetry, don't use JS CDNs. I don't think you have to go quite as far as I do, though - I imagine if your ads are Google AdSense or something, you're probably going to be fine.
Yes, I choose to use pnpm but opt-in safety isn't going to get the developer community to herd immunity.
1. https://pnpm.io/settings#allowbuilds
2. https://pnpm.io/cli/approve-builds
As the name implies it's for building stuff. Most (all?) packages that use C++ FFI with node-gyp need it. A popular package that needs it is re2.
Many newer packages bundle prebuilt native code as transitive dependencies, so build scripts are less needed than before.
Historically it was to accommodate packages like the original SASS compiler:
https://sass-lang.com/ruby-sass/
Other times it was to avoid shipping binaries due to, erm, safety concerns. The package would include code in a different language, which in turn would compile into a binary library or executable.
Most packages should not need arbitrary code execution during install. And when they do, that should be obvious during review.
The default should probably be: install files, don’t run code.
Node is working on a similar permission model to Deno that allows explicitly granting certain system resource permissions https://nodejs.org/api/permissions.html. Using it should help reduce impact from malicious code, though if you allow wide permissions it's unlikely to help.
I spent a week with claude and codex re-implementing several packages which had dependency trees deeper than I would like.
Most of these packages are trivial to clone.
"But now you're not getting the upstream fixes" they will say.
"So what?" I reply
Deno at first tried to focus only on web-like/browser-like package management with a focus on full URLs ("https://mypackage.example.com/v2/mypackage.js") and importmaps (a JSON file mapping "mypackage" to a URL such as the previous example) and package/file caching over installing. Deno 2 made Node-compatibility a higher priority (partly because of Bun's competition, partly because of complaints that Deno was hard to migrate to piecemeal from existing Node codebases) and one of those initiatives was a more npm-compatible package manager out of the box (that can also speak Node package.json and manage a node_modules directory), even as Deno still encourages for greenfield projects the URL/importmap/caching approach (with the expansion that it also understands `npm:` pseudo-URLs, `jsr:` pseudo-URLs [an alternative package registry with a stronger focus on ESM and Typescript types], and `node:` pseudo-URLs [emulated node internals], beyond just browser-safe `http:` and `https:` URLs).
Edit: a more suitable strategy is to do the minimal necessary actions for appearance purposes only, as its how to focus and optimize on its interest for revenue for its shareholders.
https://www.microsoft.com/en-us/security/blog/2025/12/09/sha...
https://azure.microsoft.com/en-us/pricing/details/defender-f...
So this is presumably why they will never address this in npm itself.
What a wonderful marketing opportunity! Leave it to Microsoft to blindly ignore it.
All that ease-of-development is being paid for by ease-of-rooting.
not as easy as docker, but i have a few bash scripts that simplify things for me a lot
i hope that this protects me from the sweep attacks at least
Since then, I had set up libvirt/qemu based VM with another Linux running in it specifically for development. Now I run all of docker, kubernetes, IDE, pnpm, uv, etc in that VM and removed them from host. The only write capable secret VM has access to, is my passphrase protected ssh key, which I can quickly revoke from my Github account in case of compromise. Feels much safer now.
pnpm audit —fix for example will whitelist releases in cooldown phase when theres a known security issue for a version you currently use.
Some are still on npm but marked "deprecated":
https://www.npmjs.com/package/size-sensor/v/1.0.4?activeTab=...
As the article states, you can see in the package.json that the optionalDependencies references "@antv/setup": "github:antvis/G2#7cb42f57561c321ecb09b4552802ae0ac55b3a7a"
I'm pretty sure those commits have been removed from github:
https://github.com/antvis/G2/issues/7401#issuecomment-448480...
https://github.com/antvis/G2/issues/7394
Compared to calling in air support on cyber criminals.
How’s your reading comprehension coming along?
Socialism or our right communism would probably fix this.
But only as a second order effect of fucking everything.
3.5 to 6 million Ukrainians died in the Holodomor.
None of them really had any issues with technology. Not so much because they didn’t have any, but more so because they were dead.
My understanding is that the problem is more that calling in the heavy artillery for what amounts to an annoyance, and maybe some financial harm, is generally considered impolite, even among nations that have conflicting worldviews.
NPM - NPM Packaged Malware
The culture makes a difference.
Now how many other mainstream languages of any kind have a standard library that is so lacking?
Now how many other mainstream languages have a swathe of front-end developers that suddenly realised they can run code in a CLI or on a server, and spent exactly 0 minutes learning about how to make it not shit?
Now how many other languages get used in scenarios where it makes absolutely zero sense because the developer only knows javascript?
I signed up for an npm account and pushed packages. Same for PyPI. Same for Ruby gems.
There's no actual reason why anyone should believe I pushed anything but malware in there.
— <https://itnext.io/no-way-to-prevent-this-says-only-developme...>
The Onion article this joke refers to [1] is funny because there is a very clear and obvious reason why the U.S. has far more gun deaths per capita. This doesn't apply for npm.
[1] https://theonion.com/no-way-to-prevent-this-says-only-nation...
Edit: please explain. What other community has this rate of attacks? It's possible they are just detected or publicized less, too. Please help me understand what you're referring to.
But... Node's culture does not reward "rational" policies with respect to dependency management in the same way that the US does not reward "rational" policies with respect to gun control *. But US gun control policy is a reflection of the "will of the electorate" -- i.e. there are a lot of Americans who want (or need) to own firearms. In the same way, NPM reflects the culture of high-speed, sili-valley web-devs.
I mention both not to criticize, but to comment it's not the tool that's at fault here, but the users who demanded it evolve the way it did. We moved fast. We broke things. And some of the things that remained broken were sociological: It's easy enough to add PGP/GPG signatures on packages, but whom do you trust? What is the meaning of a signature? Does it mean the signer warrants the package/version is free from defects?
NPM is working as designed. Users wanted the software construction equivalent of a loaded revolver. But we got something that was a bit more like a nuclear weapon with a large blast radius. At least the revolver user would more-likely only shoot their own feet six times (or twelve if they reload.)
[*] I'm trying very hard not to start a flame-war about gun control, I only mean to point out dependency management in node can be as contentious in it's domain as gun control policy is in the domain of US politics. Note that I am not making a pro or con argument about gun control, but only pointing out the issue exists. The word "rational" is intentionally chosen to reflect the fact that people's opinions on gun control and package management are often based on personal, often emotional beliefs (which should not be dismissed.)*
That is like people defending IIS in the early days by pointing out that Apache occasionally had security problems too. Or, back to the gun control analogy people saying “gun control didn't stop Bondi Beach, did it?” or pointing out [incorrectly]⁴ that everywhere that has gun control has knife crime⁴ instead.
> because there is a very clear and obvious reason why … . This doesn't apply for npm.
I disagree. There are a number of reasons that stack together, the four that spring to the top of my head being:
1. Numbers. There are a lot of potential targets you can exploit if you manage to get something into a ecosystem that large. This “being a big fat target” combined with being easy to exploit makes NPM a very juicy target, and encouraging people to use such a target without trying to implement countermeasures for this sort of attack is IMO reprehensible. Numbers isn't a problem in itself, like in the bad old days when IIS was a mess but Apache got (successfully) attacked far less, but they do exacerbate the security issue by multiplying the attack surface area.
1b. A lot of those using it are relatively untrained or just following recipes so do not know how to protect themselves, and may not even update after an attack like this and remain vulnerable for some further time. While this is not NPM's fault, being due to the popularity/commonality thing, it is something those in control of NPM should care about, if, as I believe is claimed, they care about their users⁰.
2. It is an environment where a ridiculous amount of dependencies, nested impressively deep, is practically encouraged, making audit very difficult even for those who try.
3. A number of good suggestions have been made that would mitigate, or at least vastly reduce, the risks. But action on these has, as far as we know, not happened. Sometimes for good reasons, or at least for reasons¹ rather than “just because”/“cost to implement”/“we don't wanna”, and sometimes, well, not. And no alternatives from within those running NPM are being suggested/worked-on, as far as we know² at least.
4. Those who would make most noise about any change, especially a breaking change that affects them in the smallest way, simply do not care about the risk the situation poses to the wider population.
While the gun control analogy might be a little stretched, I think it is relevant enough particularly because of points 3 & 4.
--------
[0] I refuse to use the word community here. This isn't a cosy little village where everyone knows your name and everyone looks out for everyone else.
[1] Them bringing significant breaking changes, or being too complex to implement piecemeal to give time for those breaks are dealt with or otherwise prepared for, for instance.
[2] If something was being looked into, I'd expect it to be announced³ as that would quieten criticisms like these, at least a little.
[3] Maybe not immediately, but this has been a known problem for so long that we are well past immediately.
[4] When it isn't the case that the US doesn't have knife crime, it just doesn't get reported because the gun issues are worse. Like car travel killing more in total then flights, but you don't hear about every car crash. The UK is often given as an example in these comparisons, but if you look at the stats our knife crime rates are lower than the US's - it isn't that other countries have knife problems instead, the US has worse knife problems as well as the guns problem.
What are the other ones? Does this happen with the same sort of frequency?
As long as developers in the ecosystem are cavalier about installing huge chains of dependencies, NPM will be an attractive target for attackers.
Even though we wish it were not so, cultural problems seem to be the hardest technical problems to solve.
The issue is that github actions has too many security gaps that are easy to miss.
If the attackers spearfish folks who hold “keys to the castle” and everything is digital it’s game over no matter what ecosystem.
Those things should be locked down by “something you have” because that’s much more difficult.
There is crowing from the "Actually copy-paste is better" people when this happens, but when it's their turn they just jam their fingers in their ears. The memory safety and gun safety problems are the actual problem. Shai-Hulud would ruin your day if it got into the Odin release you used to build your software, or it was copy-pasted into your "vendor everything" C++ project, the choice not to have automation doesn't mean you fixed the problem.
[1] Guns are a core part of culture for much of America, very deeply so outside coastal cities. Most of the left wing in the US lives in coastal cities and either grew up there or immigrated very recently and does not leave, so this is an alien concept to them, but even in very blue cities like D.C. you would be shocked how many liberal democrats have armories. It is literally amendment #2!
[2] They are already widely distributed and it would be a logistical impossibility to actually enforce gun control.
This is directly analogous to NPM where:
[1] The package registry working the way it does and people quickly installing packages without thinking much is deeply part of JS culture. It doesn't help that JS caters very heavily to as wide of a market as possible, of which the majority is going to be entry level/junior to associate engineers for whomst script kiddying or letting AI install whatever is essentially a way of life. As evidence, this type of thing is not really a problem with derivatives like Bun, especially in mature organizations where it's easy to enforce a minimum 72 hour wait time between publish and installation of a package.
[2] Packages are already widely distributed and part of dependency stacks (e.g. the infamous leftpad) where it is a logistical impossibility to change how things work.
I also view startups and companies like Vercel as essentially the NRA here, Next.js has taken over huge swathes of the ecosystem and highly encourages dependency-maxxing.
Another direct analogy: proponents of gun control say they are unnecessary for self defense (esp. because law enforcement is good now), too heavy duty to begin with, and fundamentally dangerous.
Similarly I would criticize dependency-maxxing as unnecessary for capability (esp. because AI is good now), too heavy duty to begin with, and fundamentally dangerous.
Sad.
I'm not following. Whats the 2nd Amendment equivalent for memory safety? The amount of C/C++ in production or something?
(maybe workshop this)
Don't make braindead My First C Program mistakes?
But aside from the package-size / -complexity issue pointed out in a sibling comment, PyPI also tries a fair bit to monitor for incoming malware (and there's a "report project as malware" button on each project page).
Also, there are no post-install scripts (of course, the code can detect when it's being run for the first time in the installed environment); and pre-install scripts are only included in sdists[0]. So you can easily[1] configure your installer such that you at least won't get pwned at install time, at the cost that some[2] packages can't be installed that way. And then you can go inspect, run a security scanner over, etc. whatever got installed; wheel installations just copy things to well-defined locations and generate simple wrapper scripts by strict rules.
[0]: I.e., when the project is "being built from source", which generally is only necessary when it includes non-Python code directly and the maintainer hasn't pre-built that code for your system.
[1]: Notwithstanding that, with pip, many actions that you'd expect not to get you pwned totally can. Such as, for example, explicitly telling it to download an sdist and not install it; as I discussed in https://zahlman.github.io/posts/python-packaging-3/ .
[2]: In practice, a pretty small fraction of what typical developers would actually care about, at least outside of specific niches. I'm told there are some niches where it's a big problem, but honestly they're lucky that this kind of build-install orchestration sort-of works at all.
Cargo is essentially the same as NPM though, it's only "safer" because it's less popular.
Although the situation on NPM is extremely uncomfortable, you're probably less likely to get hit if you take reasonable precautions than on PyPI, simply because NPM is getting scanned more often. Most of these attacks on NPM have been detected and pulled days before my min age kicks in. A sleeper attack on PyPI could be devastating.
We've had such issues on other places as well... Shai-Hulud got into Maven [1] and PHP Composer [2], typosquatters got into Maven [3], and it's not new either [4].
No one is safe from skiddies, much less from nation state actors.
[1] https://thehackernews.com/2025/11/shai-hulud-v2-campaign-spr...
[2] https://semgrep.dev/blog/2026/malicious-intercom-php-package...
[3] https://www.esecurityplanet.com/threats/malicious-jackson-lo...
[4] https://socket.dev/blog/malicious-maven-package-exfiltrates-...
Wake me up when the daily npm security breach headlines are typosquatting stories, not RCE-on-build or RCE-on-upgrade.
RCE-on-build/upgrade can be done in Maven if you manage to compromise one of the major Maven plugins, they run at build time. The thing keeping maven safe for now is that most people pin the plugin and dependency versions, with the obvious side effect that it's truly annoying to get all your dependencies updated.