6 ms·
> I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem. I see this odd take a l
by lucideer 1y ago
> I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem.
I see this odd take a lot - the automatic narrowing of the scope of an attack to the single ecosystem it occurred in most recently, without any real technical argument for doing so.
What's especially concerning is I see this take in the security industry: mitigations put in place to target e.g. NPM, but are then completely absent for PyPi or Crates. It's bizarre not only because it leaves those ecosystems wide open, but also because the mitigation measures would be very similar (so it would be a minimal amount of additional effort for a large benefit).
- woodruffw 1y agoCould you say more about what mitigations you’re thinking of? I ask because think the directionality is backwards here: I’ve been involved in packaging ecosystem security for the last few years, and I’m generally of the opinion that PyPI has been ahead of the curve on implementing mitigations. Specifically, I think widespread trusted publishing adoption would have made this attack less effective since there would be fewer credentials to steal, but npm only implemented trusted publishing recently[1]. Crates also implemented exactly this kind of self-scoping, self-expiring credential exchange ahead of npm. (This isn’t to malign any ecosystem; I think people are also overcorrect in treating this like a uniquely JavaScript-shaped problem.) [1]: https://github.blog/changelog/2025-07-31-npm-trusted-publishing-with-oidc-is-generally-available/ https://github.blog/changelog/2025-07-31-npm-trusted-publish...
- kibwen 1y ago> PyPI has been ahead of the curve on implementing mitigations Indeed, crates.io implemented PyPI's trusted publishing and explicitly called out PyPI as their inspiration: https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/ https://blog.rust-lang.org/2025/07/11/crates-io-development-...
- kees99 1y agoI agree other repos deserve a good look for potential mitigations as well (PyPI too, has a history of publishing malicious packages). But don't brush off "special status" of NPM here. It is unique in that JS being language of both front-end and back-end, it is much easier for the crooks to sneak in malware that will end up running in visitor's browser and affect them directly. And that makes it a uniquely more attractive target.
- znort_ 1y agonpm in itself isn't special at all, maybe the userbase is but that's irrelevant because the mitigation is pretty easy and 99.9999% effective, works for every package manager and boils down to: 1- thoroughly and fully analyze any dependency tree you plan to include 2- immediately freeze all its versions 3- never update without very good reason or without repeating 1 and 2 in other words: simply be professional, face logical consequences if you aren't. if you think one package manager is "safer" than others because magic reasons odds are you'll find out the hard way sooner or later.
- tbrownaw 1y agoYour item #1 there may be simple, but that's not the same as being easy.
- znort_ 1y agoagreed, bad wording. it so happens though that sw development includes many problems and practices that aren't easy and are still part of the job.
- moi2388 1y agoGood luck with nr 1 in the js ecosystem and its 30k dependencies 50 branches deep per package
- godshatter 1y agoAs an outsider looking in as I don't deal with NPM on a daily basis, the 30k dependencies going 50 branches deep seems to be the real problem here. Code reuse is an admiral goal but this seems absurd. I have no idea if these numbers are correct or exaggerations but from my limited time working with NPM a year or two ago it seems like it's a definite problem. I'm in the C ecosystem mostly. Is one NPM package the equivalent of one object file? Can NPM packages call internal functions for their dependencies instead of relying so heavily on bringing in so many external ones? I guess it's a problem either way, internal dependencies having bugs vs supply chain attacks like these. Doesn't bringing in so many dependencies lead to a lot of dead code and much larger codebases then necessary?
- weinzierl 1y agoWhich mitigations specifically are in npm but not in crates.io? As far as I know crates.io has everything that npm has, plus - strictly immutable versions[1] - fully automated and no human in the loop perpetual yanking - no deletions ever - a public and append only index Go modules go even further and add automatic checksum verification per default and a cryptographic transparency log. Contrast this with docker hub for example, where not even npm's basic properties hold. So, it is more like docker hub ⊂ npm ⊂ crates.io ⊂ Go modules [1] Nowadays npm has this arguably too
- lucideer 1y agoTo clarify (a lot of sibling commenters misinterpreted this too so probably my fault - can't edit my comment now): I'm not referring to mitigations in public repositories (which you're right, are varied, but that's a separate topic). I'm purely referring to internal mitigations in companies leveraging open-source dependencies in their software products. These come in many forms, everything from developer education initiatives to hiring commercial SCA vendors, & many other things in between like custom CI automations. Ultimately, while many of these measures are done broadly for all ecosystems when targeting general dependency vulnerabilities (CVEs from accidental bugs), all of the supply-chain-attack motivated initiatives I've seen companies engage in are single-ecosystem. Which seems wasteful.
- kibwen 1y ago> Go modules go even further and add automatic checksum verification per default Cargo lockfiles contain checksums and Cargo has used these for automatic verification since time immemorial, well before Go implemented their current packaging system. In addition, Go doesn't enforce the use of go.sum files, it's just an optional recommendation: https://go.dev/wiki/Modules#should-i-commit-my-gosum-file-as-well-as-my-gomod-file https://go.dev/wiki/Modules#should-i-commit-my-gosum-file-as... I'm not aware of any mechanism which would place Go's packaging system at the forefront of mitigation implementations as suggested here.
- WD-42 1y agoI mostly agree. But NPM is special, in that the exposure is so much higher. The hypothetical python+htmx web app might have 10s of dependencies (including transitive) whereas your typical Javascript/React will have 1000s. All an attacker needs to do is find one of many packages like TinyColor or Leftpad or whatever and now loads of projects are compromised.
- skydhash 1y agoStuff like Babel, React, Svelte, Axios, Redux, Jest… should be self contained and not depend on anything other than being a peer dependency. They are core technological choices that happens early in the project and is hard or impossible to replace afterwards.
- WorldMaker 1y ago- I feel that you are unlikely to need Babel in 2025, most things it historically transpiled are Baseline Widely Available now (and most of the things it polyfilled weren't actually Babel's but brought in from other dependencies like core-js, which you probably don't need either in 2025). For the rest of the things it still transpiles (pretty much just JSX) there are cheaper/faster transpilers with fewer external dependencies and runtime dependencies (Typescript, esbuild). It should not be hard to replace Babel in your stack: if you've got a complex webpack solution (say from CRA reasons) consider esbuild or similar. - Axios and Jest have "native" options now (fetch and node --test). fetch is especially nice because it is the same API in the browser and in Node (and Deno and Bun). - Redux is self-contained. - React itself is sort of self-contained, it's the massive ecosystem that makes React the most appealing that starts to drive dependency bloat. I can't speak to Svelte.
- johnny22 1y agoLast i checked react's new compiler still depends on babel! :(
- WorldMaker 1y ago
- simiones 1y agoMost people have addressed the package registry side of NPM. But NPM has a much, much bigger problem on the client side, that makes many of these mitigations almost moot. And that is that `npm install` will upgrade every single package you depend on to its latest version that matches your declared dependency, and in JS land almost everyone uses lax dependency declarations. So, an attacker who simply publishes a new patch version of a package they have gained access to will likely poison a good chunk of all of the users of that package in a relatively short amount of time. Even if the projects using this are careful and use `npm ci` instead of `npm install` for their CI builds, it will still easily get developers to download and run the malicious new version. Most other ecosystems don't have this unsafe-by-default behavior, so deploying a new malicious version of a previously safe package is not such a major risk as it is in NPM.
- lucideer 1y ago> in JS land almost everyone uses lax dependency declarations They do, BUT. Dependency versioning schemes are much more strictly adhered to within JS land than in other ecosystems. PyPi is a mishmash of PEP 440, SemVer, some packages incorrectly using one in the format of the other, & none of the 3 necessarily adhering to the standard they've chosen. Other ecosystems are even worse. Also - some ecosystems (PyPi again) are committing far worse offences than lax versioning - versionless dependency declaration. Heavy reliance on requirements.txt without lockfiles where half the time version isn't even specified at all. Astral/Poetry are improving the situation here but things are still bad. Maven land is full of plugins with automated pom.xml version templating that has effectively the same effect as lax versioning, but without any strict adherence to any kind of standard like semver. Yes, the situation in JS land isn't great, but there are much worse offenders out there.
- simiones 1y agoThe point is still different. In PyPI, if I put `requests` in my requirements.txt, and I run `pip install -r requirements.txt` every time I do `make build`, I will still only get one version of requests - the latest available the first time I installed it. This severely reduces the attack radius compared to NPM's default, where I would get the latest (patch) version of my dependency every day. And the ecosystem being committed to respecting semver is entirely irrelevant to supply chain security. Malicious actors don't care about semver. Overall, publishing a new malicious version of a package is a much lesser problem in virtually any ecosystem other than NPM; in NPM, it's almost an automatic remote code execution vulnerability for every NPM dev, and a persistent threat for many NPM packages even without this.
- jacques_chester 1y agoMost of the biggest repositories already cooperate through the OpenSSF[0]. Last time I was involved in it, there were representatives from npm, PyPI, Maven Central, Crates and RubyGems. There's also been funding through OpenSSF's Alpha-Omega program for a bunch of work across multiple ecosystems[1], including repos. [0] https://github.com/ossf/wg-securing-software-repos https://github.com/ossf/wg-securing-software-repos [1] https://alpha-omega.dev/grants/grantrecipients/ https://alpha-omega.dev/grants/grantrecipients/
- worik 1y agoThe Rust folks are in denial about this