There's indeed a serious problem if cache invalidation relies solely on the declared semver of the package. Maybe something govulncheck could manage by comparing a package's hash on pkg.go.dev VS the remote vcs.
If you just invalidate the cache on hash mismatch, the malware problem exists the other way around:
You update a dependency to version x and check its code to ensure it's safe. Then the threat actor adds malware to that library you're depending on, and makes the old tag x point to the malicious commit. Yor coworker does "go get" to download dependencies and gets the malware.
One solution (on dev side) is to vendor, which Go has native support for. Another (on Go side) is to show a warning on hash mismatch.
That's why I suggested govulncheck; it can keep a database of suspicious packages and issue a clear warning, and it can be locally check that the hash of tagged version you're using locally is the same on GitHub.
Yeah, it's fundamentally flawed because git tags can be force-pushed over and this has happened on many open source projects in the past, leading to different mirrors hosting different content for the same version.
the micro-dependency scheme used by go, rust, js and others is to blame.
makes it far too easy for people to pull in libraries for just about any task, even if it can be coded in just 5 lines. this often results in simple apps having hundreds of recursive dependencies.
a C programmer thinks twice whether to use a 3rd party library, because users will have to install it using their distro package manager. so they generally stick to what's commonly available there or write their own 20 lines for micro-tasks. one of the benefits that come along with that is that these distro packages are usually well vetted.
Some might not know this, hence I'm pointing it out:
There's an ENV variable that you can set in your dotfiles [1] to make the Go tooling skip any proxy and instead access the the module's repository directly:
export GOPROXY="direct"
I've had this in my ENV for a long time, primarily because I don't agree with how the Go proxy operates. For teams/organizations, as well as CI environments it also makes sense to set up an own proxy [2] and use this variable to let the toolchain use that instead.
While this wouldn't have completely prevented this incident from having an effect, I would argue that it would have at least minimized the impact.
8 comments
[ 2.6 ms ] story [ 36.3 ms ] threadYou update a dependency to version x and check its code to ensure it's safe. Then the threat actor adds malware to that library you're depending on, and makes the old tag x point to the malicious commit. Yor coworker does "go get" to download dependencies and gets the malware.
One solution (on dev side) is to vendor, which Go has native support for. Another (on Go side) is to show a warning on hash mismatch.
" Go Supply Chain Attack: Malicious Package Exploits Go Module Proxy Caching For" - https://news.ycombinator.com/item?id=42927365
a C programmer thinks twice whether to use a 3rd party library, because users will have to install it using their distro package manager. so they generally stick to what's commonly available there or write their own 20 lines for micro-tasks. one of the benefits that come along with that is that these distro packages are usually well vetted.
export GOPROXY="direct"
I've had this in my ENV for a long time, primarily because I don't agree with how the Go proxy operates. For teams/organizations, as well as CI environments it also makes sense to set up an own proxy [2] and use this variable to let the toolchain use that instead.
While this wouldn't have completely prevented this incident from having an effect, I would argue that it would have at least minimized the impact.
[1]: https://github.com/mrusme/dotfiles/blob/772f09615cdcac94fec9... [2]: https://github.com/goproxy/goproxy