We manage your security to weather the AI storm →

← Resource Hub

The tj-actions/changed-files Compromise Explained

By Owen Thurm Published 5 min read

The tj-actions/changed-files Compromise Explained

Quick answer. In March 2025, attackers repointed the tags of tj-actions/changed-files, a GitHub Action used in over 23,000 repositories, to code that printed CI secrets into build logs. Runner network monitoring caught it; pinning to commit SHAs avoids moved tags.

Watch: The tj-actions/changed-files Compromise Explained 1:40
Video transcript

In March 2025, attackers repointed every tag of a popular GitHub Action to code that printed CI secrets into build logs.

That action, tj-actions changed-files, was used in over 23,000 repositories, per Unit 42 and StepSecurity.

Unit 42 traces a token chain. A malicious pull request on SpotBugs leaked a maintainer's token, which exposed a reviewdog token. A swapped reviewdog tag then leaked write access to tj-actions, and on March 14 every tag was repointed.

The code read secrets from runner memory and printed them into workflow logs. StepSecurity found no evidence they were sent out, but public repository logs were readable by anyone.

A version tag is a pointer, and pointers can move. GitHub recommends pinning actions to a full commit SHA, which cannot be repointed.

Network monitoring caught it. The payload fetched its script from a GitHub gist, and StepSecurity's Harden-Runner flagged that unexpected endpoint.

Audit runs of the action from March 12 to 15, and rotate any exposed secret. Then pin actions to full SHAs, make the default GitHub token read-only, and drop pull request target where you can.

Guardian's Infrastructure Pentest tests this surface: build and deploy permissions, secrets handling, and vendor consoles like source control, across AWS, GCP, Azure and GitHub.

Read the full article for the timeline and audit steps, or talk to Guardian about what a compromised pipeline could reach.

A CI pipeline holds the keys a team ships with: cloud credentials, npm tokens, deploy keys and GitHub tokens.

In March 2025, one compromised GitHub Action put thousands of repositories at risk, according to Palo Alto Networks' Unit 42. It is tracked as CVE-2025-30066.

Unit 42 says the attack first targeted Coinbase's open source agentkit project, then widened. It reports Coinbase's statement that the attack caused no damage.

What Happened

The action, tj-actions/changed-files, reports which files and directories changed in a commit or pull request. A workflow can reference it by a version tag or by a commit SHA.

By March 14, 2025, an attacker had pushed a malicious commit to the repository. That day, they moved the action's tags to point at it.

NVD says tags v1 through v45.0.7 were affected on March 14 and 15.

The commit was disguised as coming from renovate[bot], Unit 42 says. Any workflow that referenced a tag pulled the new code on its next run.

That code read secrets from the runner's memory and printed them into the workflow log. CISA says they included access keys, GitHub personal access tokens, npm tokens and private RSA keys.

StepSecurity found no evidence the secrets were sent to an outside server. In public repositories, though, anyone could read the logs.

How the Attack Worked

Unit 42's updated analysis of April 2, 2025 traces a chain of stolen tokens across three projects.

  1. SpotBugs, December 2024. A malicious pull request abused a pull_request_target workflow to leak a maintainer's personal access token.
  2. reviewdog, March 11, 2025. That token let the attacker run a SpotBugs workflow that leaked a reviewdog maintainer's token.
  3. A brief tag swap. The attacker moved reviewdog/action-setup's v1 tag to malicious code from 18:42 to 20:31 UTC.
  4. The pivot. tj-actions/eslint-changed-files depended on reviewdog/action-setup. Running it leaked a token with write access to tj-actions/changed-files.
  5. The broad attack, March 14. With that token, the attacker repointed every tag of tj-actions/changed-files to the malicious commit at 16:57 UTC.

The payload

The malicious commit added a Base64-encoded payload, Unit 42 says. It downloaded a Python script from a GitHub gist and ran it with sudo, per GitHub's advisory.

The script read the memory of the Runner.Worker process and filtered it for secrets. The action then printed them to the log, Base64-encoded twice, StepSecurity says.

Unit 42 says the code did not appear to include remote code execution or a reverse shell. Its effect was disclosure.

Timeline and Exposure

Date (UTC)EventSource
Nov 28, 2024Token added to a SpotBugs workflowUnit 42
Dec 6, 2024Malicious pull request leaks that tokenUnit 42
Mar 11, 2025reviewdog v1 tag moved for under two hoursUnit 42
Mar 14, 2025All tj-actions tags repointed; detected the same dayUnit 42, StepSecurity
Mar 15, 2025CVE published; GitHub pulls the action, then restores clean versionsNVD, StepSecurity
Mar 18, 2025CISA publishes its alertCISA

Here is the exposure, with each figure attributed.

  • Reach: over 23,000 repositories used the action, per Unit 42 and StepSecurity.
  • Severity: NVD scores CVE-2025-30066 at 8.6, High.
  • Window to audit: CISA says to check any use from March 12, 00:00 UTC, to March 15, 12:00 UTC.
  • Fix: version 46.0.1, per CISA and GitHub's advisory.
  • Status: CISA added CVE-2025-30066 to its Known Exploited Vulnerabilities catalog on March 18, 2025.
  • Loss: none of the advisories we read puts a dollar figure on it.

What It Shows

A tag is a pointer, not a release

Tags can be moved after the fact. Once the attacker repointed them all, the version number in a workflow file no longer pinned anything.

GitHub's guidance is to "Pin references to actions to a commit SHA in your workflow files." A full commit SHA cannot be repointed.

CI secrets are production secrets

The tokens in a runner can publish packages, push code and reach cloud accounts. A build log is one more place they can land.

One token opened the next

Each stolen token unlocked the next project. The chain began with a pull_request_target workflow, a trigger GitHub says to avoid "if it's not necessary."

GitHub also advises setting the default GITHUB_TOKEN permission to read-only for repository contents.

Network monitoring caught it

StepSecurity's Harden-Runner flagged an unexpected endpoint in a workflow's network traffic. The payload fetched its script from gist.githubusercontent.com.

A build step calling a new domain deserves an alert.

Checks to run now

  • Pin every third-party action to a full commit SHA, and review SHA bumps like code.
  • Set the default GITHUB_TOKEN to read-only and grant write per job.
  • Remove pull_request_target where you can.
  • Prefer short-lived credentials to long-lived tokens in CI.
  • Alert on new network destinations from your runners.
  • Keep an inventory of the actions you run, so an advisory can be matched fast.
  • Write a rotation runbook. CISA said exposed secrets "should be considered compromised."

For a full pipeline template, see our smart contract CI/CD pipeline. For storage and rotation, read secrets management for crypto companies.

How Guardian Tests This Surface

Guardian's Infrastructure Pentest covers the servers, accounts and vendors a protocol depends on. Guardian escalates through cloud accounts "like an intruder, until something signs."

Three parts of its scope match this incident:

  • Build and deploy: CI/CD runner permissions, artifact integrity, and whether a compromised pipeline can ship or sign.
  • Secrets handling: where keys and tokens live, who can read them, and rotation.
  • Vendor consoles: SaaS accounts that can change production, such as source control, and who holds admin.

It covers AWS, GCP and Azure plus the platforms on top, including GitHub, CI, Docker, Kubernetes and Terraform.

See every offchain pentest Guardian runs, or how an assumed breach pentest starts from a foothold such as a CI token.

Frequently Asked Questions

What was CVE-2025-30066?

It is the CVE for the compromised tj-actions/changed-files GitHub Action. NVD says versions before 46 let remote attackers read secrets from Actions logs, after tags v1 through v45.0.7 were moved to a malicious commit on March 14 and 15, 2025.

Were the secrets sent to the attacker?

StepSecurity found no evidence of that: the secrets were printed into workflow logs. In public repositories anyone could read those logs, so CISA said exposed secrets should be considered compromised and rotated.

How do I check whether my repositories were affected?

CISA says to audit for use of the action between March 12, 00:00 UTC, and March 15, 12:00 UTC. Check those runs' logs for output encoded in Base64 twice, decode it, and rotate any secret you find.

How do I keep a moved tag out of my builds?

Pin each action to a full commit SHA, as GitHub recommends, and review SHA changes like code. Monitoring runner network traffic adds a second check: it is how StepSecurity spotted this attack.

Sources

Find out what a compromised pipeline could reach

Guardian's Infrastructure Pentest tests CI/CD runner permissions, secrets handling and source control the way an intruder would, until something signs.