We need effect based languages now. It's the only way to guarantee policies like no network, no file access, no unsafe code or FFI for a library before it even compiles. If anyone from epic is reading this please give us a timeline for open sorucing the Verse compiler.
In the mean time I think it's possible to hack Cargo and run all build scripts in a microVM. The blast radius will be limited to malicious code in the binary instead of uploading all your CI secrets and deleting the whole hard drive.
This is why I'm building this language. It's capabilities based. Build scripts can't just do whatever the hell they want to, everything is auditable, and it layers its sandboxing.
It's for fun and anyone looking should understand that this is AI driven building with human driven design, but the goal is to demonstrate.
MicroVM this, effects that --- can we discuss security without needing to invoke bay area buzzwords?
The idea is "least privilege", and we desperately need it in computing. The precise technical mechanism we use to achieve it is less important than committing to the idea that a dependency doesn't run with full privilege of its host program and an install script doesn't run with full privilege of the programmer.
The technical mechanism is exactly the issue to figure out, there's a reason why projects don't have this and it's because different implementations have different tradeoffs.
No, the reason people haven't been doing this -- and we've had technologies for ages -- is that it's a huge pain in the ass, a "tax", that it's hard to get developers inside a company to pay, much less participants in open source ecosystems.
Look at how snap, flatpak, etc. provoke people to just turn off security rather than deal with breakages.
A new language won't help because the problem is social, not technical.
build.rs by design can run absolutely anything. There tons of build.rs scripts that invoke a whole-ass C compiler toolchain to build and link C dependencies...
It isn't so much a question of sandboxing build.rs, as fundamentally changing the way that foreign dependencies are integrated into the rust toolchain (i.e. moving from a rust-centric system like Cargo to something more general like buck2)
Sandboxing just build.rs would be
be a minor inconvenience for the attacker but a big pain for many that are in the unfortunate position to really need build scripts.
It would be more than a minor inconvenience. I can handle sandboxing my tests and production infra, but I can't handle sandboxing build scripts because I don't own that code in any sense.
Sandboxing for build scripts can't work properly. If you sandbox too much, some necessary stuff can't be done. If you sandbox too little, it has no practical value.
I mean sure, but anything the build script could do, the build artifact could also do, That is to say, if you don't trust your source why do you trust the thing it compiles into?
Doing software development outside of strict containerization, at the very least, looks increasingly prone to disaster.
Yes, we can argue about the culture of package management (as some of us have with especially npm from day one), but it's done, and your colleagues or AI sidekicks cannot be trusted not to download whatever and try to build and run it. All you can do is limit the effective blast radius.
Rust suffers from the same faults as the JS ecosystem. Any significant crate imports hundreds if not thousands of dependencies. The probability that one of the authors gets targeted by AI-assisted attacks is just too high.
Also most of these dependencies provide a breadth of features that the end package does probably not need.
I mean, yes, update your dependencies. But probably after a week or so after they've been release and tested by the first penguins willing to jump into the ocean.
Are there any plans to more seriously develop the standard library in Rust? Or is the plan to remain in this status quo where users of Rust import nonsense and the dependency tree explodes (or users are forced to invent their own wheel?).
Are there any comparisons between the state of the stdlib in C++ vs. Rust? I’d think that would serve as an excellent jumping off point to start chipping away.
The idea that Rust has a small standard library is a weird meme. Rust has an enormous standard library. Look at any Rust release and you'll see dozens of new library APIs added, and consider that Rust has about nine releases a year, meaning that Rust adds over a hundred APIs per year, and has consistently for the past ten years. Rust frequently adds things that obviate popular crates, most recently the cfg_if crate was made redundant by the new cfg_select macro. And half of every dependency graph that people wrong their hands over are actually first-party external crates provided by either the Rust organization itself or by known contributors to the project. When people say that Rust has a small standard library, mostly they seem to just mean that it doesn't include a webserver.
Oh, so it's not only "JavaScript bad and npm bad". Apparently, if your language uses third party dependency registry, you are prone to malicious code, regardless if it's Javascript or not.
Use containers for development. And reduce the amount of third party deps you import into your projects. This is only going to get worse.
Pulling in lots of dependencies creates this kind of risk regardless of the ecosystem. That being said in the JS/NPM world you tend to have a LOT more dependencies (especially indirect ones) than other languages. I saw someone do a cursory analysis and JS/Node projects tend to have 5x the number rust or ruby projects.
This is really a cultural problem not a technical one.
If it weren't a registry it would be ./configure scripts and makefiles. The issue is that sandboxing technology is kinda shit (especially x-plat) and languages don't build it in by default.
Just wondering, whenever things go wrong with Rust - why do you all (Rust devs) point the finger at JavaScript?
It’s the weirdest form of projection. More than 1 person is doing it here. It’s like the second Rust hits a failure mode you immediately go “well JavaScript is worse!”
Like that has anything to do with your failure (even if it was true)
> Just wondering, whenever things go wrong with Rust - why do you all (Rust devs) point the finger at JavaScript?
I know it is almost a sport to point fingers at the "evil rust evangelists" on HN at this point, but a quick look at the fnoef's comment history would show you that they are not a rust person.
Your account, on the other hand, is a sock puppet created specifically to bitch about rust. Pot, meet kettle?
I think we should be taking a more “batteries included” approach to language and library design. The entire reason we’re in this mess is because we’ve decided it’s ok or maybe even preferable if stdlibs are rail thin, rendering base languages near-unusable.
I can very easily build a highly functional, pleasant to use Apple platform app with 5 or fewer top level dependencies. In many cases, I reach for between 0-2 total.
There’s no reason why this can’t be replicated elsewhere. The key is to make the programming language reasonably robust with at least 80% of common non-UI dev needs built in and put the remaining 20% and UI bits into a small family of well-supported, community-embraced, preferably first party libraries.
That would make it unnecessary to pull in foreign dependencies in the overwhelming majority of projects. What few do get pulled in becomes lightweight, easily verifiable syntactic sugar or libraries with purposes too niche to be worth targeting.
Of course this approach can go wrong too. You could easily end up with a monster like Boost, but that comes down to project administration keeping creep under control and proper modular design.
This was actually the main thing that put me off of Rust. I get the argument for a small std lib. I just also don’t agree it’s worth it. Go seems to handle having a batteries included standard pin just fine.
Summary: it's cultural. Rust likely inherited the practice from Nodejs, who inherited it from Ruby. I think in Rust online spaces in particular there is also this undercurrent of "you're not smart enough to use certain parts of the language, so download libraries that handle that stuff for you."
The language also takes backwards compatibility very seriously, anything that goes into std "must be maintained forever". It is also argued that a large stdlib means the maintainers have less time to work on the language itself.
I understand not every language can have Go's amazing stdlib, but I would much prefer Pyhton's approach where every now and then some package/function from the stdlib gets deprecated/removed. Rust's 3rd party ecosystem is the worst thing from the language, worse than the compile times.
i'd like to welcome you to the hell that is c/c++ dependency management. Make? cmake? qmake? conf? autoconf? configure? autotools? submodules??? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
I'd just select a tool, vendor the libraries I need to the codebase and call it a day. Did these for Eigen, liboption++, Catch2, Easylogging++ (now archived and not maintained anymore, sadly).
Build a simple makefile, and you're off to the races.
None of those (other than submodules which is just vendoring) does dependency management. They are more configuration management than anything. C, Python, Perl (and maybe ruby?) relies on flag switches and environment variables to find all the necessary files and modules for compiling/running a script. Cmake and autoconf just configure those.
With NPM and Rust's focus on project's level dependencies, there's no longer emphasis on API stability. Instead we have breakage every months, forcing everyone on the upgrade treadmill. It's easier to audit C library because they focus mostly on security updates instead of redesigning the API for the nth time.
Rust is actively incorporating more functionality into the stdlib. The functionality of this crate has been in std since 2024. The ecosystem is just slow to update (not everything is maintained, etc).
There are two reasons you might want to use a crate, The first being that you want to use a good solid implementation that you know someone has spent more time doing and works better than almost any solution you could integrate. The second is you don't want to spend time implementing that.
Writing macros in rust is a pretty horrible experience but it's not difficult
The languages that have a poor standard library support have this issue and other languages encourage you to import tons of libraries to fix the problem.
This is why Javascript and Typescript suffer from this the most and has little to nothing to do with "popularity" and likely 9/10 of these npm packages import an external library.
Golang on the other-hand is just as popular and has a stronger standard library which people build against and it is encouraged to use its standard library rather than rolling your own or importing another package to solve the problem.
Rich official standard library vs "import tons of libraries" are not the only two options.
Java's standard library had arguably also been poor for a very long time and "import tons of libraries" just had not been practical for most of that time because the tooling and ecosystem for that did not exist yet.
The solution was apache-commons and guava. Two large libraries with everything the developers heart desired and well maintained by large organizations.
For Rust be probably will never have anything exactly like that because requirements from no-std development to fully fledged backend service are too diverse, but there is still room for a small number of well
maintained backed by reputable developers convenience libraries in my opinion.
I don't want to see a large standard library for Rust. If something is added to the standard library, then it is very difficult to change it afterwards because backwards compatibility.
It would be better to have blessed crates in crates.io. The Rust core team would release or audit them. If the blessed crates need breaking changes, it can be done by increasing their major semantic version number. That can't be done to the standard library.
Actually, there could be a "trust" level for crates: 1. blessed crates by the Rust core team, 2. trusted developers, 3. untrusted developers. Or something like that..
Go has a stronger standard library for certain use cases like basic CRUD web applications, but a lot of the Go standard library is also extremely low quality (flag, container, image, json, log, math, path, regexp, sync, time). Many of these aren't usable outside of toy use cases and have weird edge cases all over the place. Over time many will probably get new incompatible versions just like json. The container package in Go is the worst collection library in any mainstream programming language by a huge margin. It's actually astounding how bad it is.
I've never seen a non trivial Python or Go project without external dependencies. The dependency tree of comparable Go and Rust projects seem comparable, IMO.
I don't think it's just that, though I agree they are clearly correlated.
The reason I don't think it's a sufficient explanation is that there is a clear history of large, 3rd party libraries being created exactly to supplement poor standard libraries. C++ has Boost, Java has Apache Commons (though Java also has a pretty huge standard library), arguably we could even say C has Posix/Win32/Cocoa.
I believe there is some deeper cultural reason why certain language ecosystems coalesce large utility libraries, while others prefer myriad tiny dependencies.
The important difference IMO is in the small vs big libraries culture.
Lots of languages have a bad stdlib but don’t fall into the trap of having thousands of micro libraries.
The reason people do it is because it brings clout and money. Just look for articles defending micro libs: the popular ones are by people who make a living on donations, due to maintaining 1000+ packages.
And collaborating in larger libs/stdlib is hard. Plus: Rust, Node, all have a lot of visibility.
You need a good stdlib culture to avoid it (like Go did).
The reason is simple: the package manager works well. Helps if the package manager is standardized and there is a "default" registry for open source projects.
I remember the days where I had to manually put the Spring .jar files into my project. No way I am doing that for 100s of dependencies.
I don't think this is true. People like to scapegoat the JS standard library but in reality most JS implementations have pretty featureful standard libraries, especially browsers. I've never felt the need to use any third-party libraries in the javascript projects I've worked on (except for maybe `ws`).
Cargo (and PyPI) is undeniably better than NPM, which is just shockingly bad for cultural reasons. Yet it's not safe, and it's subject to the same class of exploit, as we're seeing.
Indeed, the solution is to get away from the wild soup of author-managed dependencies and go with something with an audited collection of software that is maintained by separate human beings from the known-vulnerable hackers writing the software.
And indeed Go and .NET and Java all qualify. But the gold standard here is Debian and all its downstreams.
> the solution is to get away from the wild soup of author-managed dependencies and go with something with an audited collection of software that is maintained by separate human beings from the known-vulnerable hackers writing the software.
I think we might be able to crowdsource audits. At least in the Rust ecosystem I'm confident that this is feasible with the right tooling.
It usually takes some time for an updated dependency to actually get shipped to users in a release, by which time there's a good chance the attack has been noticed.
> Why do none of these hijacks embed runtime attacks? It seems like worming the build machines is the goal, rather than compromising downstream users.
Developer machines are quite juicy targets. They tend to have all sorts of credentials lying around, so it often isn't too difficult to escalate from that to compromising AWS/GCP/etc.
On top of that there's very little preventing a compromise. Developers are inherently expected to run untrusted code, and the usual Linux / MacOS laptop probably isn't even running any kind of anti-virus protection. Want to compromise the downstream app? Now you also need to pass Play Protect & friends.
> It seems like we should be building and testing everything in bubblewrap or some other sandbox going forward.
Yes, we really should. It is frankly a miracle that it has taken so long for fetch-time / install-time code execution to start blowing up in our faces. If we are spending so much effort on run-time isolation, why are we completely ignoring all those practices during development?
I’m disappointed crates.io doesn’t have a stricter bar for serving a crate that has newly acquired a proc macro or build.rs. That seems like a trivial mitigation.
Compromising the code that is then most likely run in a test instead of compromising a build script is just a very slight inconvenience for the attacker.
I'm not particularly fond of arbitrary build scripts either, but restricting them will not help the supply chain issue in a significant way.
Also there are several ways to control build.rs execution in the Cargo ecosystem, for example with cargo-deny.
Defaults matter. It’s nice you can set this up using a plugin to protect yourself, but that doesn’t protect the ecosystem, most of which doesn’t use cargo deny.
I also disagree a build scripts is a mild convenience. A build script always runs for anyone it’s a dependency for with full access and context and often has access to secrets in CI. A compromised runtime has more limited access and requires actual invocation of code paths (if you’re lying as a dependency that’s never executed, no exploit).
Of course Rust should have language-level support for capabilities so that just invoking a function doesn’t grant it access to arbitrary disk access. But that’s a much more difficult change than tweaking the defaults for cargo.
So? Runtime code requires actually executing the malicious code path which isn’t an immediate 100% hit rate for everyone that includes it in the dependency chain. For build.rs it’s a 100% compromise of everyone it’s in the dependency chain for. Additionally, at runtime you may not have access to secrets whereas at build time you most certainly do.
Why this still happens? Why after many previous supply-chain attacks maintainers of package repositories still allow anyone uploading packages and pushing updates without security audit?
Who is funding this security audit? Are folks supposed to volunteer their free time? It's a difficult coordination problem. The best folks have come up is to delay adopting new releases by a few days and hope your dependency is popular enough that a security firm audits it for you in that timespan. If you have enough money I suppose you can start employing llms to audit things for yourself.
Languages like Rust have sources of income to be able to finance such audit.
You don't need to audit all the crap is being uploaded right now. Only really necessary and widely-used packages should be managed in a centralized way, so, auditing all of them isn't that huge task.
Well, it depends on the language: language which "capabilities" (both for the source code and for the building* ) could in theory really reduce a lot of the burden to identify supply chain attacks.
*: some research language have/had capabilities which would make supply chain attack "obvious" but for build systems I don't know if this exist.
> Who is funding this security audit? Are folks supposed to volunteer their free time?
Same people who keep the whole rust project going, a lot of those are volunteers aren't they? Not mad to think they could do the same for core packages at least
> Same people who keep the whole rust project going, a lot of those are volunteers aren't they?
Sure, but from my understanding the Rust project is generally "bottom-up" in that volunteers generally work on what they want to rather than submit their time into a pool for some kind of higher-level management to direct.
It’s absolutely mad and extremely entitled to expect that a volunteer group of developers do an order of magnitude or more additional work for no additional pay or benefits to themselves.
Not really, if you're putting out something like programming languages and tooling, people expect them to work.
Especially because Rust devs brag so much about how it's soo superior to everything else, but then these amateur mishaps happen.
Rust isn't getting the exposure it deserves, I think, partly due to arrogance within the Rust community and a mental complex about "being better than everyone else" - that mentality never works
Mozilla, Google and a couple of others are publishing their audits through cargo vet. There are also additional audits done by individuals you can use through cargo crev. Overall the number of audited crates is in the thousands and you will find audits for most of the popular crates.
In the end it is your decision to use unaudited or refuse unaudited crates.
> In the end it is your decision to use unaudited or refuse unaudited crates.
It should be the default behavior of the package manager to allow downloading only audited/trusted packages. Forcing end-users of the language to be responsible for audit of all dependencies is impractical.
These very small dependencies that are then later causing issues either due to malicious nature or incompetence, have become pervasive in computing (for some reason). I think that these should be less of an issue now than ever. Outside of the largest, most critical dependencies, you really shouldn't be pulling in small libraries anymore. Just generate the code via AI. AI is not great at large scale programming I think, but its amazing at snippets of code. Something I ran into recently, I needed to use FFT2 on some matrices, and what I was using didn't have an existing solution. Converting some numpy fft2 tests to my target language, and having a full native implementation of fft2, and an accompanying test suite so it will behave exactly like numpy fft2. A few minutes and a few thousand lines of code later, I have a trusted implementation. Saves me an external dependency, some weird glue code, and an attack vector.
We need effect based languages now. It's the only way to guarantee policies like no network, no file access, no unsafe code or FFI for a library before it even compiles. If anyone from epic is reading this please give us a timeline for open sorucing the Verse compiler.
In the mean time I think it's possible to hack Cargo and run all build scripts in a microVM. The blast radius will be limited to malicious code in the binary instead of uploading all your CI secrets and deleting the whole hard drive.
[delayed]
https://github.com/insanitybit/witchy
This is why I'm building this language. It's capabilities based. Build scripts can't just do whatever the hell they want to, everything is auditable, and it layers its sandboxing.
It's for fun and anyone looking should understand that this is AI driven building with human driven design, but the goal is to demonstrate.
MicroVM this, effects that --- can we discuss security without needing to invoke bay area buzzwords?
The idea is "least privilege", and we desperately need it in computing. The precise technical mechanism we use to achieve it is less important than committing to the idea that a dependency doesn't run with full privilege of its host program and an install script doesn't run with full privilege of the programmer.
The technical mechanism is exactly the issue to figure out, there's a reason why projects don't have this and it's because different implementations have different tradeoffs.
No, the reason people haven't been doing this -- and we've had technologies for ages -- is that it's a huge pain in the ass, a "tax", that it's hard to get developers inside a company to pay, much less participants in open source ecosystems.
Look at how snap, flatpak, etc. provoke people to just turn off security rather than deal with breakages.
A new language won't help because the problem is social, not technical.
More than that, we need capability-based languages. No capability passed to it, no permission.
Cargo desperately needs sandboxing for build.rs scripts. It’s been attempted before, but didn’t go very far¹.
¹ https://rust-lang.github.io/goals/2024h2/sandboxed-build-scr...
build.rs by design can run absolutely anything. There tons of build.rs scripts that invoke a whole-ass C compiler toolchain to build and link C dependencies...
It isn't so much a question of sandboxing build.rs, as fundamentally changing the way that foreign dependencies are integrated into the rust toolchain (i.e. moving from a rust-centric system like Cargo to something more general like buck2)
Sandboxing just build.rs would be be a minor inconvenience for the attacker but a big pain for many that are in the unfortunate position to really need build scripts.
It would be more than a minor inconvenience. I can handle sandboxing my tests and production infra, but I can't handle sandboxing build scripts because I don't own that code in any sense.
https://news.ycombinator.com/item?id=49374811
(Oh and btw, proc macros also run arbitrary code.)
Sandboxing for build scripts can't work properly. If you sandbox too much, some necessary stuff can't be done. If you sandbox too little, it has no practical value.
I mean sure, but anything the build script could do, the build artifact could also do, That is to say, if you don't trust your source why do you trust the thing it compiles into?
Never going to work. Crates must be audited for behavior before use.
`cargo add` + rust-analyzer will automatically run the build.rs before you have a chance to audit the code.
Cargo, please give me a way to whitelist build.rs.
Doing software development outside of strict containerization, at the very least, looks increasingly prone to disaster.
Yes, we can argue about the culture of package management (as some of us have with especially npm from day one), but it's done, and your colleagues or AI sidekicks cannot be trusted not to download whatever and try to build and run it. All you can do is limit the effective blast radius.
Proper and easy to use support for sandboxes at the OS level, or better yet capabilities, seems like the only long term solution.
Many things I run I want to limit to r/w a single dir, and to have to request permission to make network calls.
minimum-release-age
Thread on the post from main rust blog: https://news.ycombinator.com/item?id=49372853
Direct post link: https://blog.rust-lang.org/2026/08/20/supply-chain-attack-on...
Initial report: https://github.com/rustsec/advisory-db/issues/3161
Other vendor posts:
* https://www.stepsecurity.io/blog/arrayref-rust-crate-supply-...
* https://research.jfrog.com/post/arrayref-proc-macro1-crates-...
* https://www.aikido.dev/blog/two-popular-rust-crates-arrayref...
Rust suffers from the same faults as the JS ecosystem. Any significant crate imports hundreds if not thousands of dependencies. The probability that one of the authors gets targeted by AI-assisted attacks is just too high.
Also most of these dependencies provide a breadth of features that the end package does probably not need.
All those folks telling me to update my dependencies, this is why I don't do it. It's not laziness, it's undeniable foresight.
As long as your versions don't have any security issues...
What purpose does “undeniable” serve here? This tips over into hyperbole, in my opinion, whereas “it’s foresight” is much simpler and stronger. YMMV.
I think it was to make the tongue-in-cheek nature of the comment more apparent.
I mean, yes, update your dependencies. But probably after a week or so after they've been release and tested by the first penguins willing to jump into the ocean.
Are there any plans to more seriously develop the standard library in Rust? Or is the plan to remain in this status quo where users of Rust import nonsense and the dependency tree explodes (or users are forced to invent their own wheel?).
Are there any comparisons between the state of the stdlib in C++ vs. Rust? I’d think that would serve as an excellent jumping off point to start chipping away.
The idea that Rust has a small standard library is a weird meme. Rust has an enormous standard library. Look at any Rust release and you'll see dozens of new library APIs added, and consider that Rust has about nine releases a year, meaning that Rust adds over a hundred APIs per year, and has consistently for the past ten years. Rust frequently adds things that obviate popular crates, most recently the cfg_if crate was made redundant by the new cfg_select macro. And half of every dependency graph that people wrong their hands over are actually first-party external crates provided by either the Rust organization itself or by known contributors to the project. When people say that Rust has a small standard library, mostly they seem to just mean that it doesn't include a webserver.
Oh, so it's not only "JavaScript bad and npm bad". Apparently, if your language uses third party dependency registry, you are prone to malicious code, regardless if it's Javascript or not.
Use containers for development. And reduce the amount of third party deps you import into your projects. This is only going to get worse.
Pulling in lots of dependencies creates this kind of risk regardless of the ecosystem. That being said in the JS/NPM world you tend to have a LOT more dependencies (especially indirect ones) than other languages. I saw someone do a cursory analysis and JS/Node projects tend to have 5x the number rust or ruby projects.
This is really a cultural problem not a technical one.
If it weren't a registry it would be ./configure scripts and makefiles. The issue is that sandboxing technology is kinda shit (especially x-plat) and languages don't build it in by default.
npm is mentioned 5x on this page.
Just wondering, whenever things go wrong with Rust - why do you all (Rust devs) point the finger at JavaScript?
It’s the weirdest form of projection. More than 1 person is doing it here. It’s like the second Rust hits a failure mode you immediately go “well JavaScript is worse!”
Like that has anything to do with your failure (even if it was true)
Edit: 7 times and counting
> Just wondering, whenever things go wrong with Rust - why do you all (Rust devs) point the finger at JavaScript?
I know it is almost a sport to point fingers at the "evil rust evangelists" on HN at this point, but a quick look at the fnoef's comment history would show you that they are not a rust person.
Your account, on the other hand, is a sock puppet created specifically to bitch about rust. Pot, meet kettle?
Post on the Rust blog: https://blog.rust-lang.org/2026/08/20/supply-chain-attack-on...
Discussion: https://news.ycombinator.com/item?id=49372853
I think we should be taking a more “batteries included” approach to language and library design. The entire reason we’re in this mess is because we’ve decided it’s ok or maybe even preferable if stdlibs are rail thin, rendering base languages near-unusable.
I can very easily build a highly functional, pleasant to use Apple platform app with 5 or fewer top level dependencies. In many cases, I reach for between 0-2 total.
There’s no reason why this can’t be replicated elsewhere. The key is to make the programming language reasonably robust with at least 80% of common non-UI dev needs built in and put the remaining 20% and UI bits into a small family of well-supported, community-embraced, preferably first party libraries.
That would make it unnecessary to pull in foreign dependencies in the overwhelming majority of projects. What few do get pulled in becomes lightweight, easily verifiable syntactic sugar or libraries with purposes too niche to be worth targeting.
Of course this approach can go wrong too. You could easily end up with a monster like Boost, but that comes down to project administration keeping creep under control and proper modular design.
This was actually the main thing that put me off of Rust. I get the argument for a small std lib. I just also don’t agree it’s worth it. Go seems to handle having a batteries included standard pin just fine.
The Odin programming language does this! It has also decided not to provide a package manager.
> arrayref is a small crate of four macros.
Why do so many languages fall into this horrible practice?
There was a recent talk which explored this question (Dependency Cultures, by Richard Feldman):
https://www.youtube.com/watch?v=E82ly38YEEQ
Summary: it's cultural. Rust likely inherited the practice from Nodejs, who inherited it from Ruby. I think in Rust online spaces in particular there is also this undercurrent of "you're not smart enough to use certain parts of the language, so download libraries that handle that stuff for you."
The language also takes backwards compatibility very seriously, anything that goes into std "must be maintained forever". It is also argued that a large stdlib means the maintainers have less time to work on the language itself.
I understand not every language can have Go's amazing stdlib, but I would much prefer Pyhton's approach where every now and then some package/function from the stdlib gets deprecated/removed. Rust's 3rd party ecosystem is the worst thing from the language, worse than the compile times.
i'd like to welcome you to the hell that is c/c++ dependency management. Make? cmake? qmake? conf? autoconf? configure? autotools? submodules??? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
I'd just select a tool, vendor the libraries I need to the codebase and call it a day. Did these for Eigen, liboption++, Catch2, Easylogging++ (now archived and not maintained anymore, sadly).
Build a simple makefile, and you're off to the races.
At least, for my cases, that is.
xmake, build2, whatever msvc and xcode insist upon…
None of those (other than submodules which is just vendoring) does dependency management. They are more configuration management than anything. C, Python, Perl (and maybe ruby?) relies on flag switches and environment variables to find all the necessary files and modules for compiling/running a script. Cmake and autoconf just configure those.
With NPM and Rust's focus on project's level dependencies, there's no longer emphasis on API stability. Instead we have breakage every months, forcing everyone on the upgrade treadmill. It's easier to audit C library because they focus mostly on security updates instead of redesigning the API for the nth time.
vcpkg is pretty good. cmake is complex but very flexible. just need an llm to help and it's pretty much solved (if your dep is in autopkg)
Just like c++ thought threads wasn't a std library concern and then later changed they minds, rust will also change tac I predict
Rust is actively incorporating more functionality into the stdlib. The functionality of this crate has been in std since 2024. The ecosystem is just slow to update (not everything is maintained, etc).
There are two reasons you might want to use a crate, The first being that you want to use a good solid implementation that you know someone has spent more time doing and works better than almost any solution you could integrate. The second is you don't want to spend time implementing that.
Writing macros in rust is a pretty horrible experience but it's not difficult
They aren't trivial, at least: https://docs.rs/arrayref/0.3.9/src/arrayref/lib.rs.html#202-...
The languages that have a poor standard library support have this issue and other languages encourage you to import tons of libraries to fix the problem.
This is why Javascript and Typescript suffer from this the most and has little to nothing to do with "popularity" and likely 9/10 of these npm packages import an external library.
Golang on the other-hand is just as popular and has a stronger standard library which people build against and it is encouraged to use its standard library rather than rolling your own or importing another package to solve the problem.
Rich official standard library vs "import tons of libraries" are not the only two options.
Java's standard library had arguably also been poor for a very long time and "import tons of libraries" just had not been practical for most of that time because the tooling and ecosystem for that did not exist yet.
The solution was apache-commons and guava. Two large libraries with everything the developers heart desired and well maintained by large organizations.
For Rust be probably will never have anything exactly like that because requirements from no-std development to fully fledged backend service are too diverse, but there is still room for a small number of well maintained backed by reputable developers convenience libraries in my opinion.
I don't want to see a large standard library for Rust. If something is added to the standard library, then it is very difficult to change it afterwards because backwards compatibility.
It would be better to have blessed crates in crates.io. The Rust core team would release or audit them. If the blessed crates need breaking changes, it can be done by increasing their major semantic version number. That can't be done to the standard library.
Actually, there could be a "trust" level for crates: 1. blessed crates by the Rust core team, 2. trusted developers, 3. untrusted developers. Or something like that..
Go has a stronger standard library for certain use cases like basic CRUD web applications, but a lot of the Go standard library is also extremely low quality (flag, container, image, json, log, math, path, regexp, sync, time). Many of these aren't usable outside of toy use cases and have weird edge cases all over the place. Over time many will probably get new incompatible versions just like json. The container package in Go is the worst collection library in any mainstream programming language by a huge margin. It's actually astounding how bad it is.
I've never seen a non trivial Python or Go project without external dependencies. The dependency tree of comparable Go and Rust projects seem comparable, IMO.
I don't think it's just that, though I agree they are clearly correlated.
The reason I don't think it's a sufficient explanation is that there is a clear history of large, 3rd party libraries being created exactly to supplement poor standard libraries. C++ has Boost, Java has Apache Commons (though Java also has a pretty huge standard library), arguably we could even say C has Posix/Win32/Cocoa.
I believe there is some deeper cultural reason why certain language ecosystems coalesce large utility libraries, while others prefer myriad tiny dependencies.
The important difference IMO is in the small vs big libraries culture.
Lots of languages have a bad stdlib but don’t fall into the trap of having thousands of micro libraries.
The reason people do it is because it brings clout and money. Just look for articles defending micro libs: the popular ones are by people who make a living on donations, due to maintaining 1000+ packages.
And collaborating in larger libs/stdlib is hard. Plus: Rust, Node, all have a lot of visibility.
You need a good stdlib culture to avoid it (like Go did).
The reason is simple: the package manager works well. Helps if the package manager is standardized and there is a "default" registry for open source projects.
I remember the days where I had to manually put the Spring .jar files into my project. No way I am doing that for 100s of dependencies.
I don't think this is true. People like to scapegoat the JS standard library but in reality most JS implementations have pretty featureful standard libraries, especially browsers. I've never felt the need to use any third-party libraries in the javascript projects I've worked on (except for maybe `ws`).
Total nonsense. Python has a massive stdlib and there are malicious packages.
Can’t agree more. If you take security seriously, you should consider using Go.
Rust finally got hit... This was motivating me to swap away from Rust towards because of the huge number of dependencies. It seemed inevitable. Ginger bill was right, https://www.gingerbill.org/article/2025/09/08/package-manage...
Rust seems barely better than Node in this regard. Go or .Net or anything with a robust standard library seems like the way to go for most projects.
Cargo (and PyPI) is undeniably better than NPM, which is just shockingly bad for cultural reasons. Yet it's not safe, and it's subject to the same class of exploit, as we're seeing.
Indeed, the solution is to get away from the wild soup of author-managed dependencies and go with something with an audited collection of software that is maintained by separate human beings from the known-vulnerable hackers writing the software.
And indeed Go and .NET and Java all qualify. But the gold standard here is Debian and all its downstreams.
> the solution is to get away from the wild soup of author-managed dependencies and go with something with an audited collection of software that is maintained by separate human beings from the known-vulnerable hackers writing the software.
I think we might be able to crowdsource audits. At least in the Rust ecosystem I'm confident that this is feasible with the right tooling.
Cargo-crev already exists if you care to use it.
Why do none of these hijacks embed runtime attacks? It seems like worming the build machines is the goal, rather than compromising downstream users.
It seems like we should be building and testing everything in bubblewrap or some other sandbox going forward.
It usually takes some time for an updated dependency to actually get shipped to users in a release, by which time there's a good chance the attack has been noticed.
> Why do none of these hijacks embed runtime attacks? It seems like worming the build machines is the goal, rather than compromising downstream users.
Developer machines are quite juicy targets. They tend to have all sorts of credentials lying around, so it often isn't too difficult to escalate from that to compromising AWS/GCP/etc.
On top of that there's very little preventing a compromise. Developers are inherently expected to run untrusted code, and the usual Linux / MacOS laptop probably isn't even running any kind of anti-virus protection. Want to compromise the downstream app? Now you also need to pass Play Protect & friends.
> It seems like we should be building and testing everything in bubblewrap or some other sandbox going forward.
Yes, we really should. It is frankly a miracle that it has taken so long for fetch-time / install-time code execution to start blowing up in our faces. If we are spending so much effort on run-time isolation, why are we completely ignoring all those practices during development?
What does the malicious code actually do?
I’m disappointed crates.io doesn’t have a stricter bar for serving a crate that has newly acquired a proc macro or build.rs. That seems like a trivial mitigation.
Mitigation for what?
Compromising the code that is then most likely run in a test instead of compromising a build script is just a very slight inconvenience for the attacker.
I'm not particularly fond of arbitrary build scripts either, but restricting them will not help the supply chain issue in a significant way.
Also there are several ways to control build.rs execution in the Cargo ecosystem, for example with cargo-deny.
Defaults matter. It’s nice you can set this up using a plugin to protect yourself, but that doesn’t protect the ecosystem, most of which doesn’t use cargo deny.
I also disagree a build scripts is a mild convenience. A build script always runs for anyone it’s a dependency for with full access and context and often has access to secrets in CI. A compromised runtime has more limited access and requires actual invocation of code paths (if you’re lying as a dependency that’s never executed, no exploit).
Of course Rust should have language-level support for capabilities so that just invoking a function doesn’t grant it access to arbitrary disk access. But that’s a much more difficult change than tweaking the defaults for cargo.
As mentioned by others it’s just as easy for an attacker to modify a crate’s runtime code.
So? Runtime code requires actually executing the malicious code path which isn’t an immediate 100% hit rate for everyone that includes it in the dependency chain. For build.rs it’s a 100% compromise of everyone it’s in the dependency chain for. Additionally, at runtime you may not have access to secrets whereas at build time you most certainly do.
Why this still happens? Why after many previous supply-chain attacks maintainers of package repositories still allow anyone uploading packages and pushing updates without security audit?
Who is funding this security audit? Are folks supposed to volunteer their free time? It's a difficult coordination problem. The best folks have come up is to delay adopting new releases by a few days and hope your dependency is popular enough that a security firm audits it for you in that timespan. If you have enough money I suppose you can start employing llms to audit things for yourself.
Languages like Rust have sources of income to be able to finance such audit.
You don't need to audit all the crap is being uploaded right now. Only really necessary and widely-used packages should be managed in a centralized way, so, auditing all of them isn't that huge task.
> It's a difficult coordination problem.
Well, it depends on the language: language which "capabilities" (both for the source code and for the building* ) could in theory really reduce a lot of the burden to identify supply chain attacks.
*: some research language have/had capabilities which would make supply chain attack "obvious" but for build systems I don't know if this exist.
> Who is funding this security audit? Are folks supposed to volunteer their free time?
Same people who keep the whole rust project going, a lot of those are volunteers aren't they? Not mad to think they could do the same for core packages at least
> Same people who keep the whole rust project going, a lot of those are volunteers aren't they?
Sure, but from my understanding the Rust project is generally "bottom-up" in that volunteers generally work on what they want to rather than submit their time into a pool for some kind of higher-level management to direct.
It’s absolutely mad and extremely entitled to expect that a volunteer group of developers do an order of magnitude or more additional work for no additional pay or benefits to themselves.
Not really, if you're putting out something like programming languages and tooling, people expect them to work.
Especially because Rust devs brag so much about how it's soo superior to everything else, but then these amateur mishaps happen.
Rust isn't getting the exposure it deserves, I think, partly due to arrogance within the Rust community and a mental complex about "being better than everyone else" - that mentality never works
The core packages (things like rand and regex) are pretty closely audited in practice (albeit it might not catch a credential compromise).
This crate isn't one of them.
Mozilla, Google and a couple of others are publishing their audits through cargo vet. There are also additional audits done by individuals you can use through cargo crev. Overall the number of audited crates is in the thousands and you will find audits for most of the popular crates.
In the end it is your decision to use unaudited or refuse unaudited crates.
> In the end it is your decision to use unaudited or refuse unaudited crates.
It should be the default behavior of the package manager to allow downloading only audited/trusted packages. Forcing end-users of the language to be responsible for audit of all dependencies is impractical.
If you want that you can always use vetted package repositories like Nexus. Many companies do.
These very small dependencies that are then later causing issues either due to malicious nature or incompetence, have become pervasive in computing (for some reason). I think that these should be less of an issue now than ever. Outside of the largest, most critical dependencies, you really shouldn't be pulling in small libraries anymore. Just generate the code via AI. AI is not great at large scale programming I think, but its amazing at snippets of code. Something I ran into recently, I needed to use FFT2 on some matrices, and what I was using didn't have an existing solution. Converting some numpy fft2 tests to my target language, and having a full native implementation of fft2, and an accompanying test suite so it will behave exactly like numpy fft2. A few minutes and a few thousand lines of code later, I have a trusted implementation. Saves me an external dependency, some weird glue code, and an attack vector.