Most active commenters
  • koakuma-chan(7)

←back to thread

1208 points jamesberthoty | 33 comments | | HN request time: 3.083s | source | bottom
Show context
codemonkey-zeta ◴[] No.45261026[source]
I'm coming to the unfortunate realizattion that supply chain attacks like this are simply baked into the modern JavaScript ecosystem. Vendoring can mitigate your immediate exposure, but does not solve this problem.

These attacks may just be the final push I needed to take server rendering (without js) more seriously. The HTMX folks convinced me that I can get REALLY far without any JavaScript, and my apps will probably be faster and less janky anyway.

replies(18): >>45261086 #>>45261121 #>>45261140 #>>45261165 #>>45261220 #>>45261265 #>>45261285 #>>45261457 #>>45261571 #>>45261702 #>>45261970 #>>45262601 #>>45262619 #>>45262851 #>>45267210 #>>45268405 #>>45269073 #>>45273081 #
1. tarruda ◴[] No.45261165[source]
AFAICT, the only thing this attack relies on, is the lack of scrutiny by developers when adding new dependencies.

Unless this lack of scrutiny is exclusive to JavaScript ecosystem, then this attack could just as well have happened in Rust or Golang.

replies(6): >>45261185 #>>45261224 #>>45261255 #>>45262968 #>>45267488 #>>45274187 #
2. hsbauauvhabzb ◴[] No.45261185[source]
JavaScript does have some pretty insane dependency trees. Most other languages don’t have anywhere near that level of nestedness.
replies(4): >>45261308 #>>45261471 #>>45261685 #>>45261896 #
3. ◴[] No.45261224[source]
4. coldpie ◴[] No.45261255[source]
I don't know Go, but Rust absolutely has the same problem, yes. So does Python. NPM is being discussed here, because it is the topic of the article, but the issue is the ease with which you can pull in unvetted dependencies.

Languages without package managers have a lot more friction to pull in dependencies. You usually rely on the operating system and its package-manager-humans to provide your dependencies; or on primitive OSes like Windows or macOS, you package the dependencies with your application, which involves integrating them into your build and distribution systems. Both of those involve a lot of manual, human effort, which reduces the total number of dependencies (attack points), and makes supply-chain issues like this more likely to be noticed.

The language package managers make it trivial to pull in dozens or hundreds of dependencies, straight from some random source code repository. Your dependencies can add their own dependencies, without you ever knowing. When you have dozens or hundreds of unvetted dependencies, it becomes trivial for an attacker to inject code they control into just one of those dependencies, and then it's game over for every project that includes that one dependency anywhere in their chain.

It's not impossible to do that in the OS-provided or self-managed dependency scenario, but it's much more difficult and will have a much narrower impact.

replies(1): >>45262448 #
5. staminade ◴[] No.45261308[source]
Don't they?

I just went to crates.io and picked a random newly updated crate, which happened to be pixelfix, which fixes transparent pixels in pngs.

It has six dependencies and hundreds of transient dependencies, may of which appear to be small and highly specific a la left-pad.

https://crates.io/crates/pixelfix/0.1.1/dependencies

Maybe this package isn't representative, but it feels pretty identical to the JS ecosystem.

replies(1): >>45261384 #
6. koakuma-chan ◴[] No.45261384{3}[source]
It depends on `image` which in turn depends on a number of crates to handle different file types. If you disable all `image` features, it only has like 5 dependencies left.
replies(1): >>45261462 #
7. staminade ◴[] No.45261462{4}[source]
And all those 5 remaining dependencies have lots of dependencies of their own. What's your point?
replies(1): >>45261588 #
8. cxr ◴[] No.45261471[source]
It's not possible for a language to have an insane dependency tree. That's an attribute of a codebase.
replies(2): >>45262259 #>>45262954 #
9. koakuma-chan ◴[] No.45261588{5}[source]
> What's your point?

Just defending Rust.

> 5 remaining dependencies have lots of dependencies of their own.

Mostly well-known crates like rayon, crossbeam, tracing, etc.

replies(1): >>45262478 #
10. rixed ◴[] No.45261685[source]
This makes little sense. Any popular language with a lax package management culture will have the exact same issue, this has nothing to do with JS itself. I'm actually doing JS quasi exclusively these days, but with a completely different tool chain, and feel totally unconcerned by any of these bi-weekly NPM scandals.
11. BrouteMinou ◴[] No.45261896[source]
Rust is working on that. It's not far behind right now, leave it a couple of years.
12. WD-42 ◴[] No.45262259{3}[source]
Maybe the language should have a standard library then.
replies(1): >>45262486 #
13. skydhash ◴[] No.45262448[source]
If you try installing npm itself on debian, you would think you are downloading some desktop environment. So many little packages.
14. johnisgood ◴[] No.45262478{6}[source]
You cannot defend Rust if this is reality.

Any Rust project I have ever compiled pulled in over 1000 dependencies. Recently it was Zed with its >2000 dependencies.

replies(1): >>45262797 #
15. skydhash ◴[] No.45262486{4}[source]
C library is smaller than Node.js (you won’t have HTTP). What C have is much more respectable libraries. If you add libcurl or freetype to your project, it won’t pull the whole jungle with them.
replies(2): >>45263387 #>>45266734 #
16. koakuma-chan ◴[] No.45262797{7}[source]
I think it's justified for Zed. It does a lot of things.
replies(1): >>45264272 #
17. orbital-decay ◴[] No.45262954{3}[source]
Modern programming languages don't exist in a vacuum, they are tied to the existing codebase and libraries.
replies(2): >>45264151 #>>45267432 #
18. tomjen3 ◴[] No.45262968[source]
That, and the ability to push an update without human interaction.
19. int_19h ◴[] No.45263387{5}[source]
What C doesn't have is an agreed-upon standard package manager. Which means that any dependency - including transitive ones! - requires some effort on behalf of the developer to add to the build. And that, in turn, puts pressure on library authors to avoid dependencies other than a few well-established libraries (like libpng or GLib),
20. cxr ◴[] No.45264151{4}[source]
Whatever you're trying to say, you aren't.
21. rudedogg ◴[] No.45264272{8}[source]
Zed isn’t special, I doubt Sublime Text has thousands of dependencies. It’s a language/culture problem.

Edit: Ghostty is a good counter-example that is open source. https://github.com/ghostty-org/ghostty/tree/main/pkg

replies(1): >>45266706 #
22. koakuma-chan ◴[] No.45266706{9}[source]
Zed is closer to IntelliJ or VSCode than to Sublime Text.
replies(1): >>45270137 #
23. koakuma-chan ◴[] No.45266734{5}[source]
You can add curl to a Rust project too.
replies(1): >>45270294 #
24. kelnos ◴[] No.45267432{4}[source]
Sort of, but I don't really buy this argument. Someone could go and write the "missing JS stdlib" library that has no dependencies of its own. They could adopt release policies that reduce the risk of successful supply chain attacks. Other people could depend on it and not suffer deep dependency trees.

JS library authors in general could decide to write their own (or carefully copy-paste from libraries) utility functions for things rather than depend on a huge mess of packages. This isn't always a great path; obviously reinventing the wheel can come with its own problems.

So yes, I'd agree that the ecosystem encourages JS/TS developers to make use of the existing set of libraries and packages with deep dependency trees, but no one is holding a gun to anyone's head. There are other ways to do it.

25. zelphirkalt ◴[] No.45267488[source]
At least in the JS world there are more people (often also more inexperienced people) who will add a dependency willy-nilly. This is due to many people starting out with JS these days.
26. biggusdickus69 ◴[] No.45270137{10}[source]
In the amount of bloat, yes.
replies(1): >>45277037 #
27. aakkaakk ◴[] No.45270294{6}[source]
But why, when reqwest is enough for 99% of cases.
replies(3): >>45270603 #>>45278194 #>>45281451 #
28. koakuma-chan ◴[] No.45270603{7}[source]
It's bloated.
29. user34283 ◴[] No.45274187[source]
There is little point in you scrutinizing new dependencies.

Many who claim to fully analyze all dependencies are probably lying. I did not see anyone in the comments sharing their actual dependency count.

Even if you depend only on Jest - Meta's popular test runner - you add 300 packages.

Unless your setup is truly minimalistic, you probably have hundreds of dependencies already, which makes obsessing over some more rather pointless.

30. johnisgood ◴[] No.45277037{11}[source]
It is also important to note that this is not specific to Zed. As someone else have mentioned, it is a cultural problem. I picked Zed as an example because that is what I compiled the last time, but it is definitely not limited to Zed. There are many Rust projects that pull in over 1000 dependencies and they do much less than Zed.
replies(1): >>45279323 #
31. WD-42 ◴[] No.45278194{7}[source]
It requires Tokio, and believe it or not there are actual cases for non-async rust. So you can't use it in that case.
32. koakuma-chan ◴[] No.45279323{12}[source]
Yeah tbh one time I had a Rust job and their back-end had like 700-800 dependencies.
33. bigstrat2003 ◴[] No.45281451{7}[source]
Because it requires using async, and for most programs async is not worth the extra effort (plus very heavy dependency in the form of Tokio).