Internet security research and reporting
Analysis Updated Retrospective · 2025 CVE-2025-30066

tj-actions: fixing the workflow was only the start of secret recovery

The March 2025 compromise connected mutable action tags, secret-bearing logs and credentials that could outlive the malicious code.

Mutable action tag; Malicious job execution; Secret-bearing output; Reusable downstream authority. Original diagram of the incident mechanism and review boundaries.
FISRO schematic: Mutable action tag; Malicious job execution; Secret-bearing output; Reusable downstream authority. FISRO

Summary

The tj-actions/changed-files compromise, CVE-2025-30066, redirected action tags and exposed CI/CD secrets in workflow logs in March 2025. This retrospective separates dependency adoption from affected execution and traces recovery through job permissions, exposed output and credential invalidation.

A familiar version tag pointed at different code

In March 2025, the tj-actions/changed-files GitHub Action was compromised. StepSecurity reported detecting unexpected outbound behaviour and investigating code that exposed CI/CD secrets in workflow logs. GitHub's advisory, CVE-2025-30066, records a malicious period on 14–15 March and explains that multiple version tags were redirected to malicious code.

The advisory lists action releases through 45.0.7 as affected and 46.0.1 as patched. These are the historical advisory boundaries. They do not establish that every repository using the action executed it during the malicious window, possessed a valuable secret or published a readable leaked log.

The build log became part of the exposure

A workflow runner often has authority that a source-code contributor does not: package publication, deployment, access to cloud services or signing operations. If code running in that job extracts secrets and prints them, the log is no longer a harmless diagnostic record. Its audience, retention and copies become incident-response questions.

The immediate fix is to stop executing the compromised dependency. The recovery task is broader: establish which jobs ran, what permissions and secrets they had, who could read the resulting output, and which credentials require revocation or rotation. A clean action revision cannot invalidate a credential already copied elsewhere.

Record What to collect Decision it supports
Workflow execution Run identity, timing and resolved action revision Whether the suspect code actually ran
Job authority Token permissions and available credentials Potential downstream reach
Log exposure Repository visibility and access to outputs Who could have obtained printed material
Recovery Revocation, rotation and downstream review Whether exposed authority remains usable

Pinning improves identity; review establishes trust

GitHub's secure-use guidance recommends pinning actions to a full-length commit SHA and checking that the commit belongs to the intended repository. A mutable tag is a convenient update label; it is weaker evidence of the exact code a workflow will execute.

Pinning does not independently establish that a chosen commit is safe. Review the action and its transitive execution, minimise job permissions, and avoid granting sensitive secrets to jobs that do not need them. Update pinned dependencies through a reviewable process so immutability does not become permanent abandonment of security maintenance.

FISRO recommends recording both the dependency revision and the job's authority in a release evidence package. Code identity without permissions misses the impact; permissions without identity miss the entry point.

Recover in the order authority can be reused

Identify affected executions first. Preserve the necessary forensic evidence with restricted access; avoid copying secret-bearing logs into tickets or public chat. Disable the suspect workflow path and follow the platform's current procedures for removing exposed output while retaining appropriate incident evidence.

Prioritise revocation and rotation using what each credential could do, not simply where it was stored. A deployment token, a package-publishing token and a short-lived read-only token create different downstream questions. Review relevant cloud, registry or package activity during the period in which an exposed credential could have been reused.

For persistent self-hosted runners, assess the runner environment separately. A repaired workflow file does not establish the state of a machine on which untrusted code previously executed. Follow the organisation's rebuild and incident-handling procedures rather than assuming the next clean job overwrote all earlier effects.

What xz teaches about the comparison

The xz case compromised release and build material; tj-actions redirected the code behind action tags. Both show why dependency trust must be tied to a specific artefact and execution route. Neither supports a claim that every open-source dependency is equally risky.

The connection to session theft is also operational: stopping the acquisition mechanism and invalidating the acquired authority are two different tasks. That separation should be visible in the incident checklist.

Locate use sites without executing a workflow

In an authorised local repository, search the workflow definitions for the affected action reference:

rg -n 'tj-actions/changed-files@' .github/workflows

The command reads files. It does not resolve the historical tag, execute the action or inspect workflows in other repositories. Include reusable workflows and organisation-level templates in the inventory through their own authorised access paths.

A current pinned commit or cleaned tag is not evidence of what a past run resolved. Preserve the run's recorded revision, timing, job permissions and relevant dependency metadata. If the available records do not establish the resolved code, retain that limitation instead of quietly substituting today's tag target.

A recovery sequence for exposed job authority

First identify executions during the malicious window using the advisory and available platform evidence. Then establish which secrets and token permissions the corresponding jobs could access. Public logs create a different disclosure audience from restricted private logs, but neither makes executed secret-reading code harmless.

Prioritise reusable credentials by the actions they permit and the period they remained usable. A package-publishing token warrants a publication-history review; a deployment identity warrants a review of relevant deployment and cloud activity. Removing a secret-bearing log limits continued exposure through that copy, but does not invalidate a value already obtained elsewhere.

For a persistent self-hosted runner, assess machine state separately. A new clean workflow can execute on an environment altered by the earlier job. Retain the runner identity and follow the organisation's trusted-rebuild process where compromise is supported or cannot be acceptably excluded.

Pinning needs an update and review policy

A full commit SHA gives a stronger code identity than a mutable version tag. It does not prove the selected commit is benign or that its transitive commands cannot fetch other code. Review the action's actual execution and the permissions of the job consuming it.

Keep a reviewable update route for pinned actions. Otherwise a control introduced to make code identity stable can become a reason never to adopt later security corrections. The responsible team should be able to identify the chosen revision, why it was accepted and how changes are evaluated.

Three distinct supply-chain boundaries

3CX's 2023 investigation traced compromise into a vendor's build environment. xz in March 2024 put generated release material and build conditions under scrutiny. Shai-Hulud in September 2025 added propagation through publishing credentials available during dependency installation.

For tj-actions, the specific boundary was execution of action code selected through mutable tags, followed by exposure of the job's authority in logs. That determines the evidence to preserve: resolved code, execution window, accessible credentials and log audience. A package adoption count cannot substitute for those execution records.

The practical closure test is that the vulnerable execution path is removed, exposed authority is invalidated or otherwise resolved, the relevant downstream activity has been reviewed and the runner environment has an acceptable trust basis. Each part should have an owner and evidence, so the last green workflow run does not conceal the remaining response work.

Affected software and fixes

ComponentAffectedFixed inStatusEvidence
tj-actions/changed-files
Exposure also depends on execution during 14–15 March 2025; updating does not revoke previously exposed credentials.
<= 45.0.7 (historical advisory range) 46.0.1 (historical advisory fix) Fix available GitHub Advisory Database (secondary)
Versions as stated by each evidence source. Last checked 30 October 2026. Check vendor advisories before acting; this table is not a substitute for them.

What to do

Locate action use sites, then determine the resolved revision and permissions of runs in the malicious window. Restrict secret-bearing logs, invalidate exposed credentials and review downstream activity; assess persistent runner state separately.

What remains unverified

Repository adoption counts are not confirmed compromise counts. Each organisation must establish actual workflow execution, available secrets, log visibility and downstream credential use.

Timeline

  1. StepSecurity detects and reports the compromised action. [StepSecurity]
  2. GitHub publishes the reviewed CVE-2025-30066 advisory. [GitHub Advisory Database]

Methodology

AI-assisted research and drafting. The article synthesises the linked primary documents; technical examples are read-only checks or proposed exercises, not claimed FISRO reproductions. Dates and product conditions are attributed to their sources. Editorial interpretation and diagrams are identified as FISRO analysis.

Sources

Primary sources are maintainers, vendors, official bodies and original documents. Secondary sources are reporting by others.

  1. Harden-Runner detection: tj-actions/changed-files action is compromised StepSecurity Primary Published 14 Mar 2025 Accessed 30 Oct 2026 Original detection, observed secret leakage and investigation timeline.
  2. tj-actions/changed-files supply-chain compromise: CVE-2025-30066 GitHub Advisory Database Secondary Accessed 30 Oct 2026 Malicious window, tag redirection and affected/patched action versions.
  3. GitHub Actions: Secure use reference GitHub Primary Accessed 30 Oct 2026 Full-length commit SHA pinning, third-party action review and permissions guidance.

Updates and corrections

  • Update · 30 October 2026, 01:39 UTC
    Expanded technical conditions, read-only diagnostics, incident comparisons and original diagrams; AI-assisted drafting disclosed. Original publication date retained.

Found an error? Request a correction. We record every substantive change on this page, as set out in our corrections policy.

Related coverage