Safeguard
Incident Analysis•

tj-actions/changed-files compromise: timeline and lessons for defenders

The tj-actions/changed-files compromise leaked CI secrets in March 2025. A sourced timeline, what the payload did and the pipeline changes that cut risk.

Safeguard Security Team
4 min read

In March 2025 the GitHub Action tj-actions/changed-files was compromised, and its tags were repointed to code that printed CI secrets into workflow logs. It is tracked as CVE-2025-30066. If your workflows ran an affected version on 14 or 15 March 2025, review those logs and rotate any secrets that were present.

What happened, in order?

The timeline below follows the Unit 42 analysis listed in the sources. All times are UTC.

  • 28 November 2024: A maintainer of a related project added a personal access token to a workflow.
  • 6 December 2024: A malicious pull request abused a workflow that used the pull_request_target trigger, which leaked that token.
  • 11 March 2025: A leaked token belonging to a reviewdog maintainer was used to tamper with reviewdog/action-setup. Its v1 tag pointed to a malicious commit from 18:42 to 20:31, then was moved back. CISA lists this as CVE-2025-30154.
  • 14 March 2025: A workflow in another project ran a malicious version of tj-actions/changed-files and leaked a token with write permission. At 16:57 all tags in tj-actions/changed-files were replaced with malicious commits. An outside security researcher detected the compromise and reported it to the maintainers.
  • 18 to 20 March 2025: Advisories were published and maintainers applied mitigations.

CISA's alert gives the affected window for tj-actions/changed-files as 12 March at 00:00 UTC to 15 March at 12:00 UTC, while the GitHub advisory says 14 to 15 March. Sources disagree slightly, so use the wider window when you search your logs.

What did the payload do?

According to the GitHub advisory, the malicious code read secrets from the memory of the runner process and printed them, base64-encoded, into the workflow log. The advisory says repositories with public logs were most exposed. Per Unit 42, the commit was pushed under a fake renovate[bot] identity and merged through a legitimate pull request. CISA notes the leaked secrets could include access keys, personal access tokens, npm tokens and private RSA keys, and that they might be double-encoded.

Why did tags not protect anyone?

A tag such as v44 is a pointer that a maintainer, or an attacker holding a maintainer's token, can move. GitHub's own hardening guidance says a tag can be moved or deleted if someone gains access to the action's repository, and recommends pinning to a full-length commit SHA. Pinning does not make the action trustworthy, but it stops silent replacement.

Detection came from outside the victims. The GitHub advisory says a runner monitoring tool flagged an unexpected outbound request. Most teams had no equivalent signal.

What do defenders learn from this?

The chain began with a token in a workflow and a privileged trigger. Every later step used trust that was never verified. Three controls break that chain at different points: SHA pinning, least-privilege tokens, and short-lived credentials that make a leaked log less valuable.

Open the CI/CD actions demo

What to do

  1. Search workflow runs from 12 to 15 March 2025 for the affected action, and decode suspicious log output twice from base64.
  2. Treat any secret present in those runs as exposed and rotate it.
  3. Upgrade to v46.0.1 or later, or pin to a verified commit SHA.
  4. Pin every third-party action to a full-length SHA and let a dependency updater propose bumps.
  5. Set the default GITHUB_TOKEN to read-only and raise permissions per job.
  6. Replace stored cloud keys with OIDC where your provider supports it.
  7. Audit workflows that use pull_request_target and remove any that check out untrusted code.
  8. Add egress monitoring on runners so an unexpected outbound call is noticed.

Quick check

Which CVE identifies the tj-actions compromise?

CVE-2025-30066. The related reviewdog/action-setup compromise is CVE-2025-30154, per CISA.

Is it safe to use the action now?

The advisory lists 46.0.1 as the patched version. Pin to a verified commit SHA of a patched release rather than a tag.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.