What Happened
In March 2025, attackers compromised the tj-actions/changed-files GitHub Action, used in approximately 23,000 repositories. The malicious code was injected to print secrets (tokens, credentials, API keys) from the runner environment to workflow logs.
Scope
- 23,000+ repositories used the compromised action
- Secrets potentially exposed include: GitHub tokens, cloud provider keys, npm tokens, Docker Hub credentials
- The attack traced back to a compromised Personal Access Token
Attack Timeline
- Attacker gains access to maintainer account via stolen/phished PAT
- Malicious commits pushed to all version tags (v45, v44, etc.)
- Repositories using
@v45(not pinned to SHA) immediately ran malicious code - Secrets leaked to logs; some logs publicly accessible
How to Detect Exposure
# Check if your workflows used the compromised action
grep -r 'tj-actions/changed-files' .github/workflows/
Review workflow run logs for unexpected output
Look for base64-encoded strings or dump-like output in logs
Hardening Your GitHub Actions
- Pin all Actions to full commit SHA, not tags:
# BAD
uses: tj-actions/changed-files@v45
# GOOD
uses: tj-actions/changed-files@a29e8b565651ce417abb5db7164b4a2b5b3b77f4
- Use Dependabot or Renovate to auto-update pinned SHAs
- Restrict
GITHUB_TOKENpermissions in workflow:permissions: contents: read - Use OIDC for cloud authentication instead of stored secrets
- Enable secret scanning and push protection in repository settings