iTranslated by AI
How Go Mitigates Supply Chain Attacks
Go The official blog posted an interesting article, so I'll try to introduce it briefly.
What is a Supply Chain Attack?
For those who might not know, I'll explain briefly. Originally, "supply chain" refers to the series of business flows from raw material procurement to manufacturing, logistics, sales, and delivery to customers. Optimizing this flow to improve productivity and reduce costs is what's known as SCM (Supply Chain Management).
Applying this to software development, the flow from product planning and design to manufacturing, delivery to customers, and subsequent maintenance and operations is also sometimes called a supply chain. Furthermore, in the case of software supply chains, it also includes building and operating new systems by combining multiple pieces of software. In today's XaaS-dominated era, software supply chain management is extremely important.
This "new system combining multiple pieces of software" is tricky for security management. From an attacker's perspective, they can damage the entire system by striking the weakest part among the combined software. This is the roughest explanation of a "supply chain attack."
Supply chain attacks can occur not only in the large scope of a system but also within a single software product. Modern software contains numerous libraries and frameworks, including FOSS; if a vulnerability is found in any of them, it becomes a vulnerability of the product itself, and by extension, a vulnerability of the systems using that product. For example, the log4j vulnerability that caused a stir at the end of last year or the recently discovered Spring4Shell can damage the software supply chain. That's why they've caused such a commotion.
How Go Mitigates Supply Chain Attacks
With that introduction out of the way, let's look at how Go-based software, which likely benefits from many third-party packages, mitigates (or tries to mitigate) supply chain attacks.
First and foremost,
every dependency is unavoidably a trust relationship
(via How Go Mitigates Supply Chain Attacks)
This is a point that should be kept in mind. I heard there were voices blaming the maintainers of the library when the log4j vulnerability was discovered, but honestly, that's an unreasonable demand. I'd probably end up saying, "Then don't use it!" (lol)[1]. Things work well when both the providers and users "collaborate" based on mutual trust.
Locking Versions with go.mod
Module mode was introduced in Go 1.11, which made it possible to control the versions of imported external packages. The go.mod file describes these "external package versions."
For more about Go packages and modules, please refer to my humble article below.
Furthermore, starting with Go 1.16, automatic downloading of modules (package + version) was prohibited. When importing external packages, you must explicitly download the module using the go get or go mod tidy command. This reduces the risk of inadvertently incorporating unknown versions.
Ensuring Module Integrity with go.sum
In Go's module mode, the hash values (SHA-256) of dependent modules involved in the build are recorded in the go.sum file. This makes it easier to detect if the code for a package of the same version has been secretly modified. For this reason, the go.sum file must be included in repository commits along with the go.mod file.
Additionally, with the release of Go 1.13, module mirroring and checksum database services were officially launched.
Since downloaded modules pass through these services and their hash values are recorded and queried, even when importing a package from a completely clean state, a certain level of integrity is guaranteed (provided someone has imported it before)[2].

via Module Mirror and Checksum Database Launched - The Go Programming Language
Thanks to this, you can no longer redo a release with the same version, but that is just how it is.
Official Repositories are Just for Show. The Higher-ups Don't Understand That
I believe this is a distinctive feature of Go, but the Go ecosystem does not have an official repository for centrally managing third-party libraries and frameworks. If you want to import a third-party package, you import it directly from the provider's VCS (such as Git) repository.
The mirroring service introduced in the previous section acts transparently as a simple proxy for the user. As a result, because the source the user refers to when actually downloading a module is limited to the mirroring service, it can be expected to reduce the number of attack points. Furthermore, the internal operations of the mirroring service are said to be isolated in a sandbox.
While an official repository is convenient from a user's perspective, from an attacker's perspective, it adds the official repository as a target in addition to each package's repository, so it is certainly questionable from a risk management standpoint. Well, people will likely have differing opinions on this approach. I think it's a very Go-like simplicity, though (lol).
The Monolith is Unbreakable
This is an important point, so I'll extract the original text as is. My apologies.
It is an explicit security design goal of the Go toolchain that neither fetching nor building code will let that code execute, even if it is untrusted and malicious. This is different from most other ecosystems, many of which have first-class support for running code at package fetch time. These “post-install” hooks have been used in the past as the most convenient way to turn a compromised dependency into compromised developer machines, and to worm through module authors.
(via How Go Mitigates Supply Chain Attacks)
So, the fact that Go executable binaries have a monolithic structure and do not require dynamic linking etc. also has security significance.[3]
“A little copying is better than a little dependency”
Apparently, this is a Go proverb. It feels like it's picking fights all over the place (lol).
(Around the 9-minute 30-second mark of this talk)
I suppose this is the most important point.
the strongest mitigation will always be a small dependency tree
(via How Go Mitigates Supply Chain Attacks)
In my personal opinion, I think the only way is to repeatedly refactor and tune things. I think it's fine to just keep "A little copying is better than a little dependency" in mind as a guideline.
References
-
Though it seems the log4j maintainers' stance is "I'll take care of it if you give me a reasonable amount of money," which I find to be a very kind response (lol). Personally, I think free-riding on FOSS is fine, but if you're free-riding, you're in no position to complain about vulnerabilities. If you want continuous guarantees or assurances for the software you use, your only option is to actively commit to the project. Demanding guarantees while paying nothing and offloading all responsibility is something only a child could get away with (lol). ↩︎
-
Use of mirroring and checksum database services can be partially restricted or disabled. ↩︎
-
This doesn't mean that mechanisms like dynamic linking cannot be used at all. For example, there is an approach like "Reducing disk usage with many executables in Go". I think Go's monolithic structure is an effective trade-off in today's environment where computing resources are abundant, but in embedded systems where resource constraints are often severe, one would likely have to agonize over the risk-benefit trade-offs. ↩︎
Discussion