Back to Blog

How One Compromised GitHub Action Leaked Thousands of Cloud Secrets

How One Compromised GitHub Action Leaked Thousands of Cloud Secrets

What the tj-actions/changed-files compromise exposed about CI trust - Lessons from CVE-2025-30066 for teams that rely on GitHub Actions

On March 14, 2025, defenders started piecing together a supply chain compromise in tj-actions/changed-files, a widely used GitHub Action. StepSecurity said the action was used in more than 23,000 repositories. That does not mean every one of those repositories was exposed. It does mean a lot of teams were depending on the same upstream component at the exact moment trust in that component broke.

The incident matters because it exposed a weak assumption that still shows up in a lot of CI pipelines: if your workflow file did not change, your risk did not change either. In this case, that was false.

The attacker moved existing version tags so workflows pinned to tags like @v35 or @v45 began pulling malicious code without maintainers changing anything in their own repositories. The payload searched runner memory for secrets and wrote findings into workflow logs. For public repositories, that created immediate exposure. For private repositories, the risk was narrower, but still serious enough to justify review and rotation.

What actually broke

The mechanics were simple enough to be dangerous.

Our threat intel indicates that a privileged token associated with the project’s bot account was abused to reassign existing tags to a malicious commit. That meant teams relying on mutable tags automatically inherited the compromise.

The payload then downloaded and ran a script that scraped the GitHub runner process for secret-like values. Wiz reported seeing exposed AWS keys, GitHub personal access tokens, npm tokens, and private keys in affected repositories.

The most important detail is not the script itself. It is the delivery model. A third-party CI dependency changed upstream, and downstream workflows trusted that change by default.

Why incidents like this get messy fast

Once a compromised action touches secrets, the problem stops being a GitHub Actions issue and becomes an environment-scoping problem.

Security teams now need to answer questions like:

  • Which repositories ran the compromised action during the exposure window?
  • Which secrets were available to those jobs?
  • Were any of those secrets tied to production systems?
  • Did any of those credentials show suspicious use after the workflow ran?
  • Which workflow practices made the blast radius larger than it needed to be?

That work usually spans platform engineering, cloud owners, identity teams, and incident response. The workflow definition lives in one place. The leaked credentials may unlock something somewhere else.

That is why this kind of event creates so much operational drag. The hardest part is rarely understanding the advisory. The hardest part is turning it into a reliable list of affected systems and the first safe actions to take.

What a solid response looks like

For teams that used tj-actions/changed-files, the immediate response was fairly clear:

  • Find every repository that referenced the action.
  • Check which workflows actually ran during the affected window.
  • Review logs for evidence of leaked secrets.
  • Rotate exposed credentials.
  • Look for post-exposure misuse.
  • Remove or replace the action.
  • Pin third-party actions by full commit SHA going forward.

That last step matters. GitHub’s own guidance is explicit here: pinning to a full-length commit SHA is the only immutable way to reference an action release. Tags are convenient, but tags can move.

Where Cantina fits

This is the part of the workflow where a platform like Cantina should help.

The useful job is not “detect every upstream compromise before it happens.” The useful job is to shorten the path from advisory to scoped response.

For an incident like this, that means:

  • identifying which repositories actually used the compromised action
  • mapping leaked credentials to real cloud and identity context
  • highlighting which exposed secrets matter most
  • triggering containment playbooks
  • opening safe remediation changes, such as SHA pinning or tighter workflow permissions

That framing is more honest and more useful than claiming a platform “solves supply chain risk.” What teams need in moments like this is faster scoping, cleaner prioritization, and less manual coordination.

The real takeaway

CVE-2025-30066 was not just a story about one compromised GitHub Action. It was a reminder that CI dependencies sit inside your trust boundary, even when the code lives somewhere else.

If your team depends on third-party actions, treat upstream tag changes as a real attack path. Use immutable pins where you can. Keep credentials short-lived. Limit workflow permissions. Make it easy to find which repos, secrets, and cloud identities are connected before the next upstream component breaks.

Our ongoing standard: help teams quickly scope exposure, decide what matters first, and push the obvious fixes through without adding more noise.

Book a demo: cantina.security