Most active commenters
  • cedws(4)

←back to thread

441 points longcat | 23 comments | | HN request time: 0.003s | source | bottom
Show context
f311a ◴[] No.45038992[source]
People really need to start thinking twice when adding a new dependency. So many supply chain attacks this year.

This week, I needed to add a progress bar with 8 stats counters to my Go project. I looked at the libraries, and they all had 3000+ lines of code. I asked LLM to write me a simple progress report tracking UI, and it was less than 150 lines. It works as expected, no dependencies needed. It's extremely simple, and everyone can understand the code. It just clears the terminal output and redraws it every second. It is also thread-safe. Took me 25 minutes to integrate it and review the code.

If you don't need a complex stats counter, a simple progress bar is like 30 lines of code as well.

This is a way to go for me now when considering another dependency. We don't have the resources to audit every package update.

replies(17): >>45039115 #>>45039225 #>>45039464 #>>45039724 #>>45039994 #>>45040021 #>>45040056 #>>45040113 #>>45040151 #>>45040162 #>>45040972 #>>45041479 #>>45041745 #>>45044165 #>>45045435 #>>45045983 #>>45052913 #
coldpie ◴[] No.45039464[source]
> People really need to start thinking twice when adding a new dependency. So many supply chain attacks this year.

I was really nervous when "language package managers" started to catch on. I work in the systems programming world, not the web world, so for the past decade, I looked from a distance at stuff like pip and npm and whatever with kind of a questionable side-eye. But when I did a Rust project and saw how trivially easy it was to pull in dozens of completely un-reviewed dependencies from the Internet with Cargo via a single line in a config file, I knew we were in for a bad time. Sure enough. This is a bad direction, and we need to turn back now. (We won't. There is no such thing as computer security.)

replies(12): >>45039683 #>>45039767 #>>45039803 #>>45039880 #>>45042370 #>>45043322 #>>45043362 #>>45045627 #>>45045717 #>>45046052 #>>45046055 #>>45046709 #
1. cedws ◴[] No.45039767[source]
Rust makes me especially nervous due to the possibility of compile-time code execution. So a cargo build invocation is all it could take to own you. In Go there is no such possibility by design.
replies(4): >>45040017 #>>45040638 #>>45042114 #>>45046170 #
2. exDM69 ◴[] No.45040017[source]
The same applies to any Makefile, the Python script invoked by CMake or pretty much any other scriptable build system. They are all untrusted scripts you download from the internet and run on your computer. Rust build.rs is not really special in that regard.

Maybe go build doesn't allow this but most other language ecosystems share the same weakness.

replies(3): >>45040142 #>>45040167 #>>45040796 #
3. cedws ◴[] No.45040142[source]
Yes but it's the fact that cargo can pull a massive unreviewed dependency tree and then immediately execute code from those dependencies that's the problem. If you have a repo with a Makefile you have the opportunity to review it first at least.
replies(2): >>45040664 #>>45041698 #
4. Bridged7756 ◴[] No.45040167[source]
In JavaScript just the npm install can fuck things up. Pre-install scripts can run malicious code.
5. pharrington ◴[] No.45040638[source]
You're confusing compile-time with build-time. And build time code execution exists absolutely exists in go, because that's what a build tool is. https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_mo...
replies(2): >>45040916 #>>45041386 #
6. pharrington ◴[] No.45040664{3}[source]
You are allowed to read Cargo.toml.
replies(1): >>45041347 #
7. pdw ◴[] No.45040796[source]
Right, people forget that the xz-utils backdoor happened to a very traditional no-dependencies C project.
replies(1): >>45043570 #
8. TheDong ◴[] No.45040916[source]
I think you're misunderstanding.

"go build" of arbitrary attacker controlled go code will not lead to arbitrary code execution.

If you do "git clone attacker-repo && cargo build", that executes "build.rs" which can exec any command.

If you do "git clone attacker-repo && go build", that will not execute any attacker controlled commands, and if it does it'll get a CVE.

You can see this by the following CVEs:

https://pkg.go.dev/vuln/GO-2023-2095

https://pkg.go.dev/vuln/GO-2023-1842

In cargo, "cargo build" running arbitrary code is working as intended. In go, both "go get" and "go build" running arbitrary code is considered a CVE.

replies(1): >>45045296 #
9. cedws ◴[] No.45041347{4}[source]
Cargo.toml does not contain the source code of dependencies nor transient dependencies.
replies(1): >>45042044 #
10. cedws ◴[] No.45041386[source]
I don't really get what you're trying to say, go get does not execute arbitrary code.
11. duped ◴[] No.45041698{3}[source]
Do you review the 10k+ lines of generated bash in ./configure, too?
replies(1): >>45047213 #
12. magackame ◴[] No.45042044{5}[source]
Welp, `cargo tree`, 100 nights and 100 coffees then it is
replies(2): >>45045623 #>>45049924 #
13. goku12 ◴[] No.45042114[source]
Build script isn't a big issue for Rust because there is a simple mitigation that's possible. Do the build in a secure sandbox. Only execution and network access must be allowed - preferably as separate steps. Network access can be restricted to only downloading dependencies. Everything else, including access to the main filesystem should be denied.

Runtime malicious code is a different matter. Rust has a security workgroup and their tools to address this. But it still worries me.

14. theteapot ◴[] No.45043570{3}[source]
xz-utils has a ton of build dependencies. The backdoor implant exploited a flaw in an m4 macro build dep.
15. thayne ◴[] No.45045296{3}[source]
But `go generate` can, and that is required to build some go projects.

It is also somewhat common for some complicated projects to require running a Makefile or similar in order to build, because of dependencies on things other than go code.

replies(1): >>45046699 #
16. marshray ◴[] No.45045623{6}[source]
Yes!

I sometimes set up a script that runs several variations on 'cargo tree', as well as collects various stats on output binary sizes, lines of code, licenses, etc.

The output is written to a .txt file that gets checked-in. This allows me to easily observe the 'weight' of adding any new feature or dependency, and to keep an eye on the creep over time as the project evolves.

17. fluoridation ◴[] No.45046170[source]
Does it really matter, though? Presumably if you're building something is so you can run it. Who cares if the build script is itself going to execute code if the final product that you're going to execute?
replies(1): >>45047492 #
18. TheDong ◴[] No.45046699{4}[source]
The culture around "go generate" is that you check in any files it generates that are needed to build.

In fact, for go libraries you effectively have to otherwise `go get` wouldn't work correctly (since there's no way to easily run `go generate` for a third-party library now that we're using go modules, not gopath).

Have you actually seen this in the wild for any library you might `go get`? Can you link any examples?

replies(1): >>45048517 #
19. cozzyd ◴[] No.45047213{4}[source]
./configure shouldn't be in your repo unless it's handwritten
replies(1): >>45049931 #
20. johannes1234321 ◴[] No.45047492[source]
With a scripting language it can matter: If I install some package I can review after the install before running or run in a container or other somewhat protected ground. Whereas anything running during install can hide all trades.

Of course this assumption breaks with native modules and with the sheer amount of code being pulled in indirectly ...

21. thayne ◴[] No.45048517{5}[source]
> Have you actually seen this in the wild for any library you might `go get`?

Not for a library, but I have for an executable. Unfortunately, I don't remember what it was.

22. johnisgood ◴[] No.45049924{6}[source]
You will need something stronger than caffeine.
23. johnisgood ◴[] No.45049931{5}[source]
Pretty much. It is called "autotools" for a reason.

Theoretically you should be able to generate the configuration scripts through "autoconf" (or autoreconf), or generate Makefile.in for configure from Makefile.am using "automake", etc.