Most active commenters
  • johnisgood(4)
  • burntsushi(4)
  • WorldMaker(3)

←back to thread

1208 points jamesberthoty | 24 comments | | HN request time: 1.81s | 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 #
lucideer ◴[] No.45261265[source]
> 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).

replies(7): >>45261389 #>>45261408 #>>45261464 #>>45262010 #>>45263376 #>>45266913 #>>45270888 #
1. WD-42 ◴[] No.45262010[source]
I 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.
replies(3): >>45262394 #>>45262453 #>>45263490 #
2. skydhash ◴[] No.45262394[source]
Stuff 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.
replies(1): >>45263639 #
3. johnisgood ◴[] No.45262453[source]
Well, your typical Rust project has over 1000 dependencies, too. Zed has over 2000 in release mode.
replies(2): >>45263514 #>>45265047 #
4. lucideer ◴[] No.45263490[source]
> NPM is special, in that the exposure is so much higher.

NPM is special in the same way as Windows is special when it comes to malware: it's a more lucrative target.

However, the issue here is that - unlike Windows - targetting NPM alone does not incur significantly less overhead than targetting software registries more broadly. The trade-off between focusing purely on NPM & covering a lot of popular languages isn't high, & imo isn't a worthwhile trade-off.

5. spoiler ◴[] No.45263514[source]
Not saying this in defence of Rust or Cargo, but often times those dependencies are just different versions of the same thing. In a project at one of my previous companies, a colleague noticed we had LOADS of `regex` crate versions. Forgot the number but it was well over 100
replies(3): >>45263778 #>>45263895 #>>45269137 #
6. WorldMaker ◴[] No.45263639[source]
- 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.

replies(2): >>45271031 #>>45274150 #
7. treyd ◴[] No.45263778{3}[source]
That seems like a failure in workspace management. The most duplicates I've seen was 3, with crates like url or uuid, even in projects with 1000+ distinct deps.
8. ◴[] No.45263895{3}[source]
9. Klonoar ◴[] No.45265047[source]
Your typical Rust project does not have over 1000 dependencies.

Zed is not a typical Rust project; it's a full fledged editor that includes a significant array of features and its own homegrown UI framework.

replies(2): >>45267992 #>>45273067 #
10. worik ◴[] No.45267992{3}[source]
What is a "typical Rust project", I wonder?
replies(1): >>45268783 #
11. cesarb ◴[] No.45268783{4}[source]
One famous example is ripgrep (https://github.com/BurntSushi/ripgrep). Its Cargo.lock (which contains all direct and indirect dependencies) lists 65 dependencies (it has 66 entries, but one of them is for itself).
replies(2): >>45269118 #>>45277060 #
12. burntsushi ◴[] No.45269118{5}[source]
Also, that lock file includes development dependencies and dependencies for opt-in features like PCRE2. A normal `cargo build` will use quite a bit fewer than 65 dependencies.

I would actually say ripgrep is not especially typical here. I put a lot of energy into keeping my dependency tree slim. Many Rust applications have hundreds of dependencies.

We aren't quite at thousands of dependencies yet though.

replies(1): >>45277112 #
13. burntsushi ◴[] No.45269137{3}[source]
That doesn't make sense. The most it could be is 3: regex 0.1.x, regex 0.2.y and regex 1.a.b. You can't have more because Cargo unifies on semver compatible versions and regex only has 3 semver incompatible releases. Plus, regex 1.0 has been out for eons. Pretty much everyone has moved off of 0.1 and 0.2.
replies(1): >>45274201 #
14. johnny22 ◴[] No.45271031{3}[source]
Last i checked react's new compiler still depends on babel! :(
replies(1): >>45278070 #
15. wolvesechoes ◴[] No.45273067{3}[source]
> Zed is not a typical Rust project; it's a full fledged editor

Funny that text editor is being presented here as some kind of behemoth, not representative of typical software written in Rust. I guess typical would be 1234th JSON serialization library.

16. user34283 ◴[] No.45274150{3}[source]
Jest alone adds 300 packages by the way.
replies(1): >>45277996 #
17. spoiler ◴[] No.45274201{4}[source]
The reason he went down this rabbit hole was because he was chronically running low on disk space, and his target dir was one of the largest contributors.

Not sure how he actually got the number; this was just a frustrated Slack message like 4 years ago

A sibling comment mentions we could have been using Cargo workspaces wrong... So, maybe?

replies(1): >>45275133 #
18. burntsushi ◴[] No.45275133{5}[source]
He probably just needed to run `cargo clean` occasionally.

But you definitely aren't finding hundreds of versions of `regex` in the same dependency tree.

19. johnisgood ◴[] No.45277060{5}[source]
Not quite. He is a better developer than most who happen to minimize dependencies, but according to my experiences it is not as common as you would like to believe. Do I really need to make a list of all the Rust projects I have compiled that pulled in over 1000 dependencies? If I need to do it to convince you, I will do so, as my time allows.
20. johnisgood ◴[] No.45277112{6}[source]
> I would actually say ripgrep is not especially typical here. I put a lot of energy into keeping my dependency tree slim. Many Rust applications have hundreds of dependencies.

Thank you for your honesty, and like you and I said, you put a lot of energy into keeping the dependency tree slim. This is not as common as one would like to believe.

replies(1): >>45277366 #
21. burntsushi ◴[] No.45277366{7}[source]
I agree it's not common. But neither are Rust applications with 1000+ dependencies. I don't think I've ever compiled a Rust project with over 1,000 dependencies.

Hundreds? Yes, absolutely. That's common.

replies(1): >>45277672 #
22. johnisgood ◴[] No.45277672{8}[source]
Maybe I am just unlucky enough to always running into Rust projects that pull in over 1000 dependencies. :D

In retrospect, I should have kept a list of these projects. I probably have not deleted these directories though, so I probably still could make a list of some of these projects.

23. WorldMaker ◴[] No.45277996{4}[source]
Yep, which is part of why it feels real good to delete Jest and switch to `node --test`. I realize for a lot of projects that is easier said than done because Jest isn't just the test harness but the assertions framework (`node:assert/strict` isn't terrible; Chai is still a good low-dependency option for fancier styles of assertions) and mocks/substitutes framework (I'm sure there are options there; I never liked Jest's style of mocks so I don't have a recommendation handy).

(ETA: Also, you may not need much for a mocks library because JS' Proxy meta-object isn't that hard to work with directly.)

24. WorldMaker ◴[] No.45278070{4}[source]
Yeah, I still don't understand a lot of the architecture choices behind the new compiler, including why the new compiler isn't mostly just a set of eslint suggestions with auto-fixes. I've seen the blog posts trying to explain it, but they don't seem to answer my questions. But then I also haven't done enough direct React work recently enough to have need of or actually tried to use the new compiler, so maybe I am just asking the wrong questions.