# Trivy Compromised a Second Time - Malicious v0.69.4 Release, aquasecurity/setup-trivy, aquasecurity/trivy-action GitHub Actions Compromised

Attacker repointed all trivy-action and setup-trivy tags to imposter commits injecting a credential stealer that read Runner.Worker memory and exfiltrated CI secrets to a typosquat C2.

- Payout: Real-world hack
- Severity: critical
- Program: Trivy
- Analysis by: StepSecurity
- Disclosed: 2026-03-26
- Write-up quality: 8/10
- Original: https://www.stepsecurity.io/blog/trivy-compromised-a-second-time---malicious-v0-69-4-release
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release
- Tags: area:oss domain:oss impact:data-leak impact:internal-access kind:incident platform:threat-intel sev:critical tech:github-actions technique:recon technique:source-review vuln:misconfiguration vuln:secrets-leak

**Target:** GitHub Actions (aquasecurity/trivy-action, aquasecurity/setup-trivy) and trivy v0.69.4 binaries
**Root cause:** Incomplete containment of a prior PAT theft let the attacker push imposter commits to forks and move all version tags to them; tags can reference any commit in the object store, so tag consumers ran malicious entrypoint.sh/action.yaml.
**Steps:**
1. Attacker obtains repo write via stolen PAT from prior pull_request_target compromise
2. Push malicious commit to fork built on top of legitimate HEAD, reusing the same commit message to disguise it
3. Move all version tags (0.0.1-0.34.2 for trivy-action; all setup-trivy tags) to the imposter commit
4. Injected step scans `/proc/*/environ` and reads `/proc/<pid>/mem` of Runner.Worker to extract `isSecret: true` values
5. Data encrypted with hardcoded RSA-4096 (AES-256-CBC + RSA-OAEP) and POSTed to `scan.aquasecurtiy.org`
6. Fallback: if C2 unreachable and GITHUB_TOKEN present, create public repo `tpcp-docs` and upload stolen data as release asset
7. Publish malicious trivy v0.69.4 binaries with same C2 hardcoded; Homebrew/helm downstream automation picks it up
**How found:** StepSecurity's Harden-Runner baselined outbound destinations per workflow step and flagged `scan.aquasecurtiy.org:443` as a never-before-seen destination across multiple community projects; process events showed python3 reading `/proc/<pid>/mem` of Runner.Worker, and GitHub's 'commit does not belong to any branch' warning identified the imposter commits.
**Exploitation:** Any CI workflow referencing a compromised tag or running trivy v0.69.4 during the exposure window executed the stealer, which harvested GITHUB_TOKEN, referenced `${{ secrets.* }}` values, and cloud/registry credentials, then exfiltrated them RSA-encrypted to the typosquat domain. Attackers then used stolen repo credentials to create new workflows in new branches to exfiltrate secrets from additional repositories.
**Escalation:** Lateral movement: stolen repo credentials used to add workflows on new branches targeting other repos' Actions secrets; fallback exfil via victim-created public repo when C2 blocked.
**Insight:** GitHub Action tags can be silently repointed to fork commits that never land on a branch — diff the tag's commit against the legitimate HEAD and watch for the 'does not belong to any branch' banner; also baseline per-step egress so a single new destination (here a typosquat) exposes supply-chain compromise.
