By completing this scenario, you will learn:
- How attackers compromise developer security tools through credential theft
- How incomplete credential rotation enables persistent access to a repository
- The mechanics of force-pushing malicious commits to existing version tags
- How CI/CD pipelines are infected through trusted security tools
- Techniques to detect and respond to security tool supply chain attacks
- Hardening strategies including SHA pinning and runtime network monitoring
CVE-2026-33634 represents one of the most significant supply chain attacks in recent history. In March 2026, a financially motivated threat group known as TeamPCP compromised Aqua Security's Trivy vulnerability scanner - a tool trusted by thousands of organizations to find vulnerabilities in their code and containers.
| Date | Event |
|---|---|
| Late February 2026 | Attackers exploited a misconfigured pull_request_target workflow in Trivy's own GitHub repo to steal a high-privilege Personal Access Token (PAT). |
| March 1, 2026 | Aqua Security detected the breach and rotated credentials - but the rotation was not atomic: not all tokens were revoked simultaneously, leaving a window. |
| March 19, 2026 | Using still-valid credentials, attackers: (1) published malicious Trivy v0.69.4 release, (2) force-pushed 76 of 77 version tags in aquasecurity/trivy-action to credential-stealing commits, (3) replaced all 7 tags in aquasecurity/setup-trivy with malicious commits. |
| March 22, 2026 | Attackers published malicious Docker images v0.69.5 and v0.69.6 on Docker Hub, GHCR, and ECR. |
- Trusted tool as attack vector - Trivy is a security scanner; organizations trusted it to find threats, not be one.
- Force-push technique - Overwriting existing tags rather than creating new releases avoids most notification triggers.
- Cascading impact - The same TeamPCP campaign later compromised Checkmarx KICS and BerriAI's LiteLLM.
- Multiple distribution channels - GitHub Releases, Docker Hub (
docker.io/aquasec/trivy), GHCR, and ECR were all affected.
The injected malware was a credential harvester that:
- Scanned environment variables, SSH keys, cloud provider credentials, Kubernetes tokens, Docker configs, and database passwords
- Exfiltrated data to the typosquatted domain
scan.aquasecurtiy[.]org(note missings) - Created public repositories named
tpcp-docsas a backup exfiltration channel - Installed persistent Python backdoors (
/tmp/.cache/pybin/) on compromised machines
You are a security engineer at a mid-sized SaaS company. Your CI/CD pipelines use Trivy for container vulnerability scanning. One Monday morning you receive a security advisory about CVE-2026-33634 and need to:
- Attacker role: Examine how the force-push attack was executed
- Victim role: Understand how the malicious action harvested CI secrets
- Defender role: Run detection tooling and implement mitigations
- Node.js 16+ and npm
cd scenarios/23-trivy-supply-chain-attack
export TESTBENCH_MODE=enabled
./setup.shsetup.sh resets infrastructure/captured-data.json, installs victim-ci dependencies (which pulls in the simulated malicious trivy-action-like@0.69.4), and prints next steps.
Use two terminals. All paths are relative to scenarios/23-trivy-supply-chain-attack.
node infrastructure/mock-c2-server.jsLeave this running. It listens on localhost:3023 and logs every exfiltration attempt.
export TESTBENCH_MODE=enabled
# 1. Review the clean scanner (the attacker's starting point)
node legitimate/trivy-scanner/index.js
# 2. Run the victim CI pipeline - watch the malicious action exfiltrate secrets
cd victim-ci
node run-pipeline.js
cd ..
# 3. Verify the exfil occurred
curl -s http://127.0.0.1:3023/captured-data | node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
console.log('Captures:', d.captures.length);
d.captures.forEach((c,i) => console.log(i+1, JSON.stringify(c.data, null, 2)));
"# After ./setup.sh - planted .env.ci-lab (same values as scenarios/_shared/lookalike-secrets.env)
set -a && source .env.ci-lab && set +a
export GITHUB_REPOSITORY=acme-corp/payments-api
cd victim-ci && node run-pipeline.js# View
curl -s http://127.0.0.1:3023/captured-data
# Clear between runs
curl -X DELETE http://127.0.0.1:3023/captured-dataFrom the scenario root (scenarios/23-trivy-supply-chain-attack/):
node detection-tools/trivy-version-scanner.js victim-ci
node detection-tools/ci-workflow-auditor.js victim-ciFrom victim-ci/ (after node run-pipeline.js):
npm run scan
npm run auditTasks:
- Compare
legitimate/trivy-scanner/index.jswithmalicious-trivy/v0.69.4/trivy-action-like.js - Review the reference CI workflow at
victim-ci/.github/workflows/ci.yml
Questions:
- How did the attackers initially gain access to Trivy's repository?
- Why was the March 1 credential rotation insufficient?
- What is force-pushing and why is it dangerous for version tags?
- Why are security tools particularly attractive supply chain targets?
Tasks:
- Run the victim CI pipeline with
TESTBENCH_MODE=enabled - Observe the exfiltration in Terminal A
- Set environment variables to simulate real CI secrets and re-run
Questions:
- Which environment variables were harvested in your run?
- What does the pipeline output show to an unsuspecting developer?
- What makes this attack hard to notice in normal CI logs?
Tasks:
- Run
trivy-version-scanner.json the victim CI directory - Run
ci-workflow-auditor.jsand review each finding - Read through
DETECT.mdfor the full detection runbook
Questions:
- Which
WF-0xcheck identifies the initial access vector used by TeamPCP? - What does a force-pushed tag look like in GitHub's audit log vs. a normal release?
- How would you determine if your organization ran affected pipelines between March 19-22?
Tasks:
- Edit
victim-ci/.github/workflows/ci.ymlto use the commented-out safe SHA reference - Re-run
ci-workflow-auditor.jsand verifyWF-02andWF-05are cleared
Questions:
- Why does pinning to a commit SHA prevent force-push attacks?
- What is
step-security/harden-runnerand how does it complement SHA pinning? - What changes to the credential rotation process on March 1 could have prevented the March 19 attack?
Use this checklist to determine if your organization was affected:
- Search all
.yml/.yamlworkflow files fortrivy-action@v0.34andsetup-trivy@v0.2.5(or earlier) - Check Docker configs for
aquasec/trivy:0.69.4,0.69.5, or0.69.6 - Inspect GitHub organization audit logs for unexpected
tpcp-docsrepository creation - Review pipeline logs from March 19-22, 2026 for unexpected network connections
- Check for
~/.ssh/id_rsa,~/.aws/credentials,~/.kube/configaccess in process logs - Rotate all secrets that were accessible to pipelines running in that window
- Contain: disable and re-queue all pipelines that ran
trivy-action@v0.34.xorsetup-trivy@v0.2.5or earlier after March 19 2026. - Eradicate: replace every mutable tag reference with an immutable commit SHA (
aquasecurity/trivy-action@<SHA>). - Recover: rotate all CI secrets (GITHUB_TOKEN, AWS keys, registry credentials, database URLs) accessible to affected pipeline runs.
- Hunt: scan every workflow YAML in the organization for compromised version strings; check Dockerfiles and container registries for
trivy:0.69.4/5/6. - Harden: enforce SHA pinning for all third-party actions via policy (e.g.
step-security/harden-runner, Allstar, or custom CI lint); alert on unexpected outbound network calls from action steps.
- CVE-2026-33634 - NVD
- GitHub Security Advisory GHSA-69fq-xp46-6x23
- Aqua Security CVE-2026-33634 Announcement
- step-security/harden-runner - blocks unexpected network calls from actions
- SLSA Framework - supply-chain levels for software artifacts
cd scenarios/23-trivy-supply-chain-attack
./clean.sh