Main content

Ken Thompson's 1984 compiler warning is today's supply chain reality. Here's how capability analysis fights back

Alyx MacQueen Profile picture for user alex_lee September 5, 2025
Summary:
Software supply chain attacks are exploiting a dangerous blind spot - the difference between the code developers review and the software that actually runs. At the Open Source Summit, Google’s Eve Martin-Jones showed how a new approach called capability analysis helps close that gap.

Abstract Internet Cyber Security concept © Vertigo3d - Canva.com

In 1984, computer scientist Ken Thompson demonstrated that the tools used to build software could themselves be compromised in ways invisible to human review. Speaking at the Open Source Summit Europe, Google's Eve Martin-Jones argues that this 40-year-old warning is playing out daily in today's open source ecosystem — the gap between code developers review and what actually runs on their systems has become a widening attack surface.

Four real-world breaches are used by the senior software engineer to show how attackers exploit this blind spot – and how capability analysis can be used as a way to close it. She explains:

Performing code review is obviously still very important. We don't want to just let anyone check anything into our source code repos. But the source of truth for security is the build artifact, not the source code, because the code that you build is not guaranteed to be the same code that you review.

Four cautionary tales of the supply chain

The first case study concerns boltdb-go, a fork of a widely used Go library. The attackers crafted a fork name almost indistinguishable from the original boltDB library, then slipped in a backdoor that connected to a remote server. They covered their tracks by changing the release label so it pointed to a clean version – meaning anyone checking the GitHub repository would see nothing unusual. The attack specifically targeted the Go module mirror, which stores immutable copies of package versions once they're published. She elaborates:

The attacker chose a name that was really similar to the name of a popular and legitimate library. This helped ensure that when they added the dependency on the malicious package to the target library, it didn't stick out as something obviously suspicious.

Next comes EventStream, a Node.js package hijacked by a new maintainer. The malicious version was hidden behind a clever use of version numbers: attackers published a tainted patch release (3.3.6) while simultaneously pushing a clean major version (4.0.0). Most downstream projects were pinned to the vulnerable branch – but anyone inspecting "the latest code" on GitHub would see only the harmless version.

The third case escalates from dependency hijacking to the Continuous Integration/Continuous Deployment (CI/CD) pipeline itself. Attackers compromise a maintainer's GitHub token and use it to inject malicious code into TJ-actions/changed-files, a widely used GitHub Action. The payload targets Coinbase, aiming to leak secrets from build runners. When the initial stealth attempt fails, the attackers broaden the strike, exposing thousands of projects to malicious code execution.

Finally, Martin-Jones recalls the notorious xz incident of 2024. A patient attacker using the name "Jia Tan" spent years cultivating credibility in the project before slipping a backdoor into release binaries. The malicious payload wasn't in the source repository at all – it lurked in binary test files unpacked only during release builds. Only luck – and a sharp-eyed Microsoft engineer – stopped it before widespread compromise.

Across these examples, one theme stands out – attackers thrive in the blind spots between human review and machine execution. Typosquatting, misleading version numbers, binary test files, dependency smuggling – all succeed by ensuring that what a reviewer sees is not what the system runs.

Capabilities, not just code

So what's the counter? Martin-Jones argues for shifting security attention from inputs to outputs – from source code to build artifacts.

The method is capability analysis. The idea is intuitive if you think of smartphone app permissions. Instead of trusting the developer's word that an app will behave, you check the list of permissions it requests: access to camera, microphone, location, contacts. You can make an informed decision if something doesn't add up.

Applied to open source, the same principle reveals what a built package is capable of. A maths library should not be opening network sockets or executing system commands. By surfacing unexpected capabilities, developers can detect potential attacks even when the code appears benign.

This is the principle behind Capslock, an open source CLI tool developed for Go. Capslock looks not only at the packages you import directly but also at the hidden chain of dependencies they pull in. It examines how functions are connected during the build process, giving a clear view of what the software can actually do. It then generates a report highlighting which capabilities the package actually uses, flagging high-risk ones like file system or network access. Martin-Jones observes:

What's really cool is that Capslock digs into the software dependencies your package is using, including those transitive dependencies that, as we saw in our case studies, are often the ones causing security issues.

Making hidden changes visible

Capslock becomes even more powerful when used for comparing capabilities between two versions of a package. In the case of the boltdb-go fork, comparing the two versions would have revealed the malicious one suddenly gaining the ability to run commands and send data over the internet – a change too significant to miss, however well hidden in the code.

The statistics reinforce the point – only three percent of Go package updates add a new capability. That rarity makes new capabilities stand out as red flags, without overwhelming reviewers with noise.

Integrating capability diffs into routine review processes could transform how teams handle dependencies. Rather than relying purely on vigilance – which attackers deliberately exhaust with noisy pull requests – maintainers would have an automated way to highlight suspicious changes.

As Martin-Jones puts it: 

Using Capslock to analyze the build artifacts, and surfacing that information to humans during code review, makes the behavior of the new or changed code more transparent, makes attacks and backdoors more difficult."

Traditional vulnerability scanning is reactive by nature, because it flags known issues after disclosure, after a Common Vulnerabilities and Exposures (CVE) identifier exists. Capability analysis shifts the model. It surfaces potential for harm before a CVE ever exists, by showing when code gains powers it shouldn't need.

The Go team has already run capability analysis across the ecosystem, publishing results on deps.dev. The Rust Foundation has launched a pilot implementation, with early results promising. There's interest in extending the approach to C# and other ecosystems.

This is where Martin-Jones sees momentum building: 

Now that you're all convinced that capability analysis is an integral way forward for software security, what's next? Well, Capslock was originally implemented just for Go, but we'd love to see it implemented across as many language ecosystems as possible.

My take

The history of software security has always been a story of expanding the perimeter of trust. Once, it was enough to lock down your own servers. Then came third-party SaaS, cloud infrastructure, open source dependencies, and now the invisible layers of CI/CD and package registries. Each expansion has required a rethink of where trust should be verified.

Capability analysis feels like a natural next step in that progression. It doesn't replace human review or community trust, but it strengthens both by illuminating the artifact that really matters – the code that ships.

For organizations that use open source at scale, this is not an abstract concern. Supply chain attacks have shown that determined attackers – whether opportunists or patient, highly organized groups – will exploit any gap between what developers review and what actually runs. Tools like Capslock don't just help close those gaps, they redefine the rules of engagement by making hidden changes visible.

The lesson from Thompson's 1984 essay still applies – trust is never absolute. But with the right tools, it can be verified.

Disclosure - The Linux Foundation covered the author's travel and accommodation costs to attend the Open Source Summit Europe.

Loading
A grey colored placeholder image