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.
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.
- SpotBugs, December 2024. A malicious pull request abused a
pull_request_targetworkflow to leak a maintainer's personal access token. - reviewdog, March 11, 2025. That token let the attacker run a SpotBugs workflow that leaked a reviewdog maintainer's token.
- A brief tag swap. The attacker moved reviewdog/action-setup's v1 tag to malicious code from 18:42 to 20:31 UTC.
- 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.
- 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) | Event | Source |
|---|---|---|
| Nov 28, 2024 | Token added to a SpotBugs workflow | Unit 42 |
| Dec 6, 2024 | Malicious pull request leaks that token | Unit 42 |
| Mar 11, 2025 | reviewdog v1 tag moved for under two hours | Unit 42 |
| Mar 14, 2025 | All tj-actions tags repointed; detected the same day | Unit 42, StepSecurity |
| Mar 15, 2025 | CVE published; GitHub pulls the action, then restores clean versions | NVD, StepSecurity |
| Mar 18, 2025 | CISA publishes its alert | CISA |
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_TOKENto read-only and grant write per job. - Remove
pull_request_targetwhere 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
- Unit 42: GitHub Actions Supply Chain Attack, A Targeted Attack on Coinbase Expanded to the Widespread tj-actions/changed-files Incident (March 20, 2025, updated April 2, 2025)
- NVD: CVE-2025-30066 (March 15, 2025)
- GitHub Advisory Database: tj-actions changed-files, GHSA-mrrh-fwg8-r2c3 (March 15, 2025)
- CISA: Supply Chain Compromise of Third-Party tj-actions/changed-files (CVE-2025-30066) and reviewdog/action-setup@v1 (CVE-2025-30154) (March 18, 2025)
- StepSecurity: Harden-Runner detection, tj-actions/changed-files action is compromised (March 14, 2025)
- CISA: Known Exploited Vulnerabilities Catalog (CVE-2025-30066 added March 18, 2025)
- GitHub Docs: Secure use reference
- GitHub: tj-actions/changed-files repository
- Guardian: Cloud and Infrastructure Penetration Testing
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.