How a Simple Script Could Have Protected 23,000 Github Repositories — tj-actions/changed-files

Recently, a Supply Chain Attack targeted tj-actions/changed-files GitHub Action Repository, having potentially exploited around 23,000 repositories, with the intent of exfiltrating credentials — CVE-2025–30066.
This post explores the issues associated with blindly trusting third-party GitHub Actions, how hackers leverage their attacks, and one possible practical way to proactively protect your repositories.
Blindly Trusting Third-Party Actions
Many repositories reference Github Actions in their workflows using a release tag (e.g., v4.0.0). While this makes updates seamless each time the runner pulls the Github Action, it also introduces a dangerous risk:
If a Github Action’s repository is compromised and malicious commits are pushed to its release tags, any dependent workflow referencing those tags will automatically fetch and execute the malicious code.
Moreover, if a repository specifies only the major version as of cool-actions@v4.0, it will automatically retrieve the most recent v4.0.x minor version release.
How It Works:
- cool-actions@4.0 → Matches any v4.0.x release, defaulting for the latest minor version in v4.0 series;
- cool-actions@4.0.0 → Locked to v4.0.0 only, won't update automatically
- cool-actions@4 → Matches any v4.x.x release (latest major version in v4.x series)
- cool-actions@main → Always pulls the latest commit on main
How Attackers Exploit This Behavior
- Injecting Malicious Code into Newer Minor Version: Pushing into a newer v4.0.x release ensures workflows using @v4.0 automatically execute the attacker's code;
- Isolating the Attack: Since minor versions v4.0.x roll up under v4.0, the changes remains confined to a specific release though impact is more broad. This allows the attacker to introduce malicious changes without altering the entire repository structure, making the attack more stealthy;
- Cleaning Up Evidence: The attacker can delete the malicious v4.0.x release after execution, removing traces of the exploit while preserving legitimate repository history;

Pinning Github Actions to Specific Commits
The antidote to the above threat is to Pin the Github Action repository to a specific commit SHA instead of referencing it by the version tag as @v4.0.x:
- name: Run unpinned action (bad example)
uses: user/cool-action@v4.0 # Vulnerable
- name: Run pinned action (good example)
uses: user/cool-action@f5c6d2e4b3a89d1d8a64a7e6d5a8c0e8e2f1b6a9 # Pinned to commit SHA
Even if the repository is compromised later, this ensures that only the intended reviewed and legit version is used.
Automated Safety Hook
Adopting a Shift-Left Security approach is crucial for strengthening security across an organization. By integrating security best practices early in the development lifecycle, teams can proactively mitigate potential threats before they become exploitable vulnerabilities. In contrast, a reactive approach often falls short, as it addresses security risks only after they have already been introduced into the system.
One effective way to implement a proactive security mindset is by enforcing pre-commit hooks in your repositories. These hooks can automatically scan workflow files for unpinned third-party Github Actions, preventing the use of untrusted or potentially compromised dependencies.
The following snippet demonstrates how engineering teams can apply this principle to protect their repositories. Specifically, in the case of the tj-actions Supply Chain Attack, this simple security measure could have safeguarded all 23,000 repositories from potential exploitation.
# Initialize your git repository
> git init
# Create the following file and set exec bit
> touch .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
# Insert following script
> cat > .git/hooks/pre-commit <<EOF
#!/bin/bash
echo "🔍 Checking for Unpinned Actions in Github Workflow Files"
# Find all Staged GitHub Actions YAML files
WORKFLOW_FILES=$(find .github/workflows -type f -name "*.yml" -o -name "*.yaml")
if [[ -z "$WORKFLOW_FILES" ]]; then
echo "✅ No modified Github Actions Workflow files detected."
exit 0
fi
# Unpinned Workflows Found (?)
UNPINNED_FOUND=0
# Commit Hash Regex
SHA_REGEX='^[a-f0-9]{40}$'
for FILE in $WORKFLOW_FILES; do
while IFS= read -r line; do
if [[ "$line" =~ uses:\ ([^@]+)@([a-zA-Z0-9._-]+) ]]; then
ACTION="${BASH_REMATCH[1]}"
REF="${BASH_REMATCH[2]}"
if ! [[ "$REF" =~ $SHA_REGEX ]]; then
echo "❌ Detected $ACTION@$REF in $FILE"
UNPINNED_FOUND=1
fi
fi
done < "$FILE"
done
if [[ "$UNPINNED_FOUND" -eq 1 ]]; then
echo "🚨 Commit rejected! Please pin all actions to a specific commit SHA."
exit 1
else
echo "✅ All actions are pinned. Proceeding with commit."
exit 0
fi
EOF
Any developer attempting to commit changes to workflow files with Unpinned Actions will be blocked, ensuring adherence to best practices when using third-party GitHub Actions.

Additional Security Measures
Beyond pinning actions to specific commits, organizations should adopt a layered security approach to further mitigate risks in their GitHub Actions workflows. The following measures can enhance security and reduce exposure to supply chain attacks:
- Monitor Dependency Vulnerabilities: Use GitHub Dependabot to automatically detect security vulnerabilities in your dependencies.
- Analyze Network Traffic: Leverage tools like StepSecurity to monitor network activity from runners and detect suspicious outbound connections.
- Harden Runner Containers: Strengthen your CI/CD runner environment by applying security best practices, such as using minimal base images, disabling unnecessary privileges, and enforcing least-privilege access.
- Restrict Third-Party Actions: Configure GitHub’s Allowed Actions policy to limit which external actions can run in your workflows, preventing unauthorized or compromised actions from being executed.
- Implement Secrets Scanning: Enable GitHub Secret Scanning or leverage other secret scraping tools to detect accidental exposure of credentials in your repository commit history before attackers can exploit them.
Conclusion
The rise of Supply Chain Attacks highlights the need for stricter security measures. By pinning actions to commit SHAs, monitoring dependencies, and implementing security best practices proactively, organizations can significantly reduce their attack surface.