Every scanner involved in the March 2025 tj-actions/changed-files attack did exactly what it was built to do. That's the part that should worry you more than a missed CVE.
One fact isn't a chain
A finding is a single fact: a leaked token, a mutable tag, a transitive dependency. Security orgs are built around single facts — SAST findings go to AppSec, SCA findings go to the dependency team, CI/CD findings go to DevOps. Each team closes its own list correctly. Nobody owns the line between the lists. That gap is where this attack lived.
The three hops
Hop 1. A personal access token sits in the GitHub Actions secrets of SpotBugs, a Java static analysis tool. Unremarkable — thousands of projects are set up exactly this way.
Hop 2. That token has write access to a second project: reviewdog, a code review automation tool.
Hop 3. Reviewdog is a dependency, a few steps removed, of tj-actions/changed-files — a GitHub Action used in 23,000+ repositories.
Token → tool that trusted it → tool that depended on that tool. Each hop, viewed in isolation, is completely fine. Together, they're a path.
The payload
With write access to tj-actions, the attacker didn't add malicious code anywhere visible. They moved the v45 tag — and others — to point at a different commit. Every workflow referencing that tag by name (the default, recommended pattern) started executing a script that printed CI/CD secrets, API keys, and cloud credentials straight into the build log, in plain text.
Detection to confirmed CVE: under 24 hours. Appearance on CISA's Known Exploited Vulnerabilities catalog: within days. The response was fast — the exposure window still mattered for anyone whose logs were public.
The 10-second check
Open a workflow file. Find a line like uses: some-action, then look at what follows the @. If it isn't a 40-character commit hash, it's a tag — and a tag can move without a single line in your workflow file ever changing.
The actual point
This incident wasn't defined by a vulnerability. It was defined by a trusted connection that quietly changed. Different stacks will produce different versions of this same shape — the hard part is never spotting a connection, it's knowing which of the hundreds of unremarkable ones deserves a second look.
Episode 3 of They Read The Manual, "Inside the Chain," walks through the full three-hop compromise and shows what real detection code for this pattern looks like.
🎥 Watch: https://youtu.be/y-QEHIk9WvQ
Top comments (0)