Most modern software has a large amount of open-source code. Because the code is constantly used and downloaded, it opens up the potential for supply chain attacks. Despite good process and technical chops, every dependency is an unavoidable trust relationship. This article discusses how Golang tries to mitigate these risks with very explicit design decisions.
In Golang, all builds are locked. The version of every dependency is set in the go.mod file. Only explicit updates to this file can change the dependencies, such as go get or go mod tidy. This is super important for security - the code in the repository for should be the source of truth and nothing else.
There is no concept of latest for dependencies. This prevents a dependency from being compromised by backdooring all of the users very quickly. Everything said above is also transitive for dependencies of dependencies as well. If a dependency is compromised, it requires a specific update as a result, giving folks time to see what's going on.
Version contents are guaranteed to never change - module versions are immutable. This property ensures that an existing package cannot be modified to compromise code that depends on it. So, if something is safe to run currently, we're confident it will be safe to run. A lot of cryptographic verification goes into this.
Another issue that I have with NPM is related to hooks or builds running code. Golang has no post-install hooks. Additionally, the built code cannot do anything until it is actually running. In all likelihood, if you installed something, you're probably going to run it, but this does add another security boundary, though.
Overall, a good look into supply chain security in Golang. I like to see that the developers put a lot of thought into the package manager of Golang.