Secret leakage isn’t always about bad code or vulnerable libraries. Sometimes, it comes down to how we manage secrets during CI runs, and CVE‑2025‑30066 is a textbook example of how that can go sideways. The GitHub Action tj‑actions/changed‑files, widely used to detect changed files in pull requests, became a silent channel for secret leakage. Here’s what happened and how you can lock down your CI/CD secrets pipeline.
What Happened in CVE‑2025‑30066?
In mid‑March 2025, tj‑actions/changed‑files was compromised. The attacker rewrote existing version tags (up to v45.0.7) to point to a malicious commit. This altered the Action’s behavior without developers noticing; no new version was released, just invisible tag tampering.
The payload was straightforward but dangerous: it pulled a remote Base64-encoded Python script that scanned runner memory for credentials, dumping them into logs or exfiltrating them. This wasn’t a logical code flaw in the tj‑actions/changed‑files; it was an abuse of how secret leakage can occur within CI workflows using that reusable Action. CVE‑2025‑30066 wasn’t about buffer overflows; it was about a CI design failure that enabled secrets to leak.
Impact: Any repo using the affected versions of tj‑actions/changed‑files risked secret leakage, especially if sensitive tokens or files were handled insecurely in file patterns or CI outputs.
Why This Affects Workflows Relying on Reusable Actions
DevSecOps workflows heavily rely on tj‑actions/changed‑files to:
- Automate pull request checks
- Identify changed files in specific paths
- Avoid redundant CI jobs
But these workflows often overlook one thing: how glob patterns might include sensitive data. Developers assume that tj‑actions/changed‑files behaves securely by default. However, if you glob configs/** and secrets are stored in configs/secrets.env, you just added a secret file into CI outputs or logs. That’s not a bug in the Action; it’s a CI/CD design failure that leads to secret leakage. CVE‑2025‑30066 is a clear example of this.
How the Secret Leakage Happened (Vulnerability Breakdown)
Let’s unpack the core failure behind CVE‑2025‑30066:
- Globbing patterns like **/*.env matched secret files unintentionally
- tj‑actions/changed‑files treated those secrets as changed files
- Secrets ended up in step outputs, logs, or downstream jobs
This happened because secrets were stored in version-controlled paths (bad idea), and the CI config didn’t explicitly exclude them from globbing (also bad). So it’s not a code bug, it’s poor CI design hygiene causing secret leakage with tj‑actions/changed‑files outputs.
Practical Exploit Path: From CI Job to Credential Exposure
Example CI setup that caused secret leakage through tj‑actions/changed‑files:
yaml
jobs:
detect_changes:
runs‑on: ubuntu‑latest
steps:
‑ uses: actions/checkout@v3
‑ name: Check changed files
id: changed
uses: tj‑actions/changed‑files@v45
with:
files: configs/**
If configs/secrets.env changed:
- It was flagged by tj‑actions/changed‑files
- It got included in steps.changed.outputs.all_changed_files
- Later steps logged it or passed it to scripts, leaking secrets
This leak happened because CI logic treated secrets like regular files. That’s where the secret leakage begins, not due to a buffer overflow, but misuse of tj‑actions/changed‑files in a flawed CI design.
Propagation happens with outputs like:
yaml
‑ name: Use changed file list
run: echo "Changed files: ${{ steps.changed.outputs.all_changed_files }}"
If secrets.env is in that list, its filename and possibly contents may surface in build logs. Even conditional logic like:
yaml
if: contains(steps.changed.outputs.all_changed_files, 'secrets.env')
Can expose sensitive artifacts. This is a CI/CD design failure allowing secret leakage, not a flaw in the Action code.
How to Safely Use Reusable Workflows and Prevent Leakage
You don’t need to abandon tj‑actions/changed‑files. You should use reusable Actions with a secrets-first mindset:
Secrets‑Handling Best Practices
- Don’t version control secrets, ever
- Avoid glob patterns that match sensitive paths
- Use environment-based secrets (GITHUB_ENV, vaults, GitHub Secrets)
CI/CD Configuration Guardrails
- Always pin Actions to immutable SHAs, not tags (never use @v45)
- Treat tj‑actions/changed‑files output as tainted, sanitize or filter it
- Set outputs only if sanitized
⚠️ Unsafe Example:
yaml
jobs:
detect_changes:
runs‑on: ubuntu‑latest
steps:
‑ uses: actions/checkout@v3
‑ name: Detect all changes
id: changed
uses: tj‑actions/changed‑files@v45
with:
files: '**/*' # ⚠️ This glob includes secrets.env, which may leak credentials
The above is exactly the misuse behind secret leakage and CVE‑2025‑30066.
Safe Alternative:
yaml
jobs:
detect_changes:
runs‑on: ubuntu‑latest
steps:
‑ uses: actions/checkout@v3
‑ name: Detect non‑sensitive file changes
id: changed
uses: tj‑actions/changed‑files@<SHA> # pinned to SHA
with:
files: 'src/**'
files‑ignore: '**/secrets.env' # ⚠️ Excludes secret file
By doing this, you avoid the CI/CD design failure that leads to secret leakage via tj‑actions/changed‑files.
Additionally:
- Disable or restrict logging where secrets might appear
- Use GitHub’s secret masking features
- Limit access to build logs and artifacts
Quick Secrets‑Safe CI Usage Checklist
Best Practice |
---|
Don’t store secrets in version‑controlled files |
Use vaults or GitHub Secrets for credentials |
Always pin tj‑actions/changed‑files to immutable SHAs |
Filter or sanitize outputs from tj‑actions/changed‑files |
Never include secret paths in glob patterns |
Mask or restrict logs that may expose sensitive data |
Audit inherited CI configs often |
Xygeni’s Role: CI Secrets Enforcement at Scale
Xygeni secures CI/CD pipelines by focusing on how secrets are handled, used, and exposed in real-world DevOps workflows. It’s not just about scanning code; it’s about enforcing secret management best practices through live pipeline analysis.
Unsafe Output Usage Detection
- Scans GitHub Actions for uses of echo, run, and outputs where ${{ steps.*.outputs.* }} might include sensitive values
- Identifies when secrets are referenced or printed directly, intentionally, or by mistake
Leaked Secrets Monitoring
- Detects high-entropy values (API keys, tokens) inside logs and step outputs
- Triggers alerts when secrets appear in the pipeline logs, even if masked downstream
Misconfigured Action Usage
- Tracks all GitHub Actions across pipelines to detect use of compromised versions (e.g., tj-actions/changed-files@v45)
- Audits file-matching patterns that include potential secrets like **/*.env, *.key, or .env.*
Policy-Based CI Guardrails
- Enforces SHA-pinning for third-party Actions
- Blocks use of unsafe file globs that could sweep secrets into logs
- Prevents pipelines from emitting sensitive values as part of workflow outputs
By treating workflows as part of your threat surface, Xygeni ensures secret hygiene is not just a best practice, it’s a built-in defense.
Conclusion: Secret Leakage Can Start with a Simple Action Misuse
CVE‑2025‑30066 wasn’t a library bug; it was a CI/CD design failure stemming from improper use of tj‑actions/changed‑files. What DevSecOps teams should take away:
- Treat every glob/file reference in CI as a potential leak point
- Audit workflows regularly for accidental inclusion of secrets
- Use secure vaults or environment secrets, never check secrets into version control
- Sanitize or filter all workflow outputs
- Log sensitive workflow activity to maintain auditability
CI is code. Workflows are code. Logs and outputs are code. Guard your secrets at every step, or risk a secret leakage scenario that doesn’t need a hacker, just a bad CI/CD design choice.