Trivy Supply Chain Compromise – Again: A Security Scanner Weaponised Across 10,000 Pipelines — and the Attacker Is Still Inside

Team PCP Thrivi Attack

Executive Summary

Aqua Security’s Trivy scanner has been compromised three times in under a month by a threat actor that still has access to the organisation’s infrastructure. What started as a stolen token from a misconfigured GitHub Actions workflow on February 28 has escalated into the most consequential CI/CD supply chain attack since the SolarWinds campaign — and as of March 23, it is not contained.

We previously covered a similar attack with TJ Actions, GitHub Action compromise, and an early article on the Action compromise. This is a deep dive

On March 19, 2026, threat actor TeamPCP compromised Aqua Security’s Trivy vulnerability scanner for the second time in three weeks (disclosed by Paul McCarty), injecting a multi-stage credential stealer into official GitHub Actions used by over 10,000 CI/CD workflows globally.

The attacker — tracked as TeamPCP — force-pushed 76 of 77 version tags in aquasecurity/trivy-action to inject a three-stage credential stealer into every CI/CD pipeline that referenced the action by tag. Over 10,000 GitHub workflow files pull trivy-action. The malicious payload dumped Runner.Worker process memory, swept 50+ filesystem credential paths, encrypted everything with AES-256 + RSA-4096, and exfiltrated it to attacker-controlled infrastructure. The legitimate Trivy scan ran after the stealer, so pipeline output looked completely normal.

Key Takeaways

  • 76 of 77 trivy-action version tags were force-pushed to malicious commits — only v0.35.0 was protected by GitHub’s immutable releases
  • Backdoored Trivy binaries v0.69.4, v0.69.5, and v0.69.6 were published to Docker Hub, GHCR, and ECR
  • Root cause: incomplete credential rotation after the February 28 hackerbot-claw breach left the attacker with residual access
  • The attacker still has access as of March 22 — Aqua confirmed “additional suspicious activity” and engaged Sygnia for incident response
  • All 44 repositories in Aqua’s internal GitHub org (aquasec-com) were defaced, exposing proprietary code and infrastructure configs
  • Stolen npm tokens triggered CanisterWorm, a self-propagating worm infecting 47+ packages via ICP canister dead-drop C2
  • The Aqua Security GPG signing key (ID E9D0A3616276FA6C, in use since 2019) must be considered compromised — it was exposed during the release build
  • Safe versions: trivy v0.69.2–v0.69.3, trivy-action v0.35.0 (SHA: 57a97c7e), setup-trivy v0.2.6
  • Update 23/3/2026:
  • v0.69.5 and v0.69.6 were Docker-only — no GitHub releases, no tags, pushed directly to the registry
  • The latest tag on Docker Hub pointed to v0.69.6 — every docker pull aquasec/trivy:latest was backdoored
  • mirror.gcr.io continued serving v0.69.4–v0.69.6 after Docker Hub removal — pipelines still pulling cached copies
  • Docker Hub tags are not immutable — same structural weakness as Git tags, now exploited in the same campaign
  • Third-party images that auto-rebuilt against affected versions are a secondary blast radius
  • Downstream tool maintainers are already revoking tokens and adopting trusted publishing Socket confirmed IOCs in the binaries: scan.aquasecurtiy.org, payload.enc, tpcp.tar.gz, tpcp-docs

TL;DR for Engineering Teams

What it is: Multi-stage supply chain compromise of Aqua Security’s Trivy scanner, trivy-action GitHub Action, setup-trivy GitHub Action, and Aqua’s internal GitHub organisation. Attributed to TeamPCP (DeadCatx3/PCPcat/ShellForce). No CVE assigned for the supply chain attack. GitHub Security Advisory: GHSA-cxm3-wv7p-598c and GHSA-69fq-xp46-6×23.

Where it bites: Any CI/CD pipeline referencing aquasecurity/trivy-action by version tag (76 of 77 tags poisoned, only v0.35.0 safe). Any pipeline pulling trivy binary v0.69.4, v0.69.5, or v0.69.6. Any pipeline using aquasecurity/setup-trivy (7 tags compromised). Old tags without a v prefix (0.0.1–0.34.2) should be considered compromised; new v-prefixed tags (v0.0.1–v0.34.2) point to original legitimate commits.

Why it matters: The stealer runs before the legitimate Trivy scan — pipeline output looks normal. It dumps Runner.Worker process memory for CI/CD secrets, sweeps 50+ filesystem credential paths on self-hosted runners (SSH, AWS/GCP/Azure, K8s, Docker, databases, crypto wallets), encrypts with AES-256 + RSA-4096, and exfiltrates silently. The attacker still has access to Aqua’s infrastructure as of March 22. Stolen credentials are being weaponised across the npm ecosystem via a self-propagating worm.

Patch status: Malicious artifacts removed from distribution channels (repeatedly — the attacker keeps returning). New v-prefixed tags published. Immutable releases enabled. Safe versions: trivy v0.69.2–v0.69.3, trivy-action v0.35.0, setup-trivy v0.2.6.

Immediate action: 1. Pin trivy-action to SHA 57a97c7e7821a5776cebc9bb87c984fa69cba8f1 — do not trust any version tag 2. Rotate ALL secrets if any pipeline ran a compromised component during any exposure window 3. Block IOCs: scan.aquasecurtiy[.]org, 45.148.10.212, tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io, and all Cloudflare Tunnel C2 domains 4. Search your GitHub org for tpcp-docs repositories (indicates successful exfiltration) 5. Check self-hosted runners and developer machines for /tmp/pglog, ~/.config/sysmon.py, pgmon.service 6. Monitor — this is an active campaign, not a contained incident

Vulnerability Overview

FieldValue
VendorAqua Security
ProductsTrivy, trivy-action, setup-trivy, aquasec-com org
Vulnerability TypeSupply chain compromise / credential theft / org takeover
CWECWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
CVENot assigned (GHSA-cxm3-wv7p-598c, GHSA-69fq-xp46-6×23)
Attack VectorNetwork (CI/CD pipeline execution)
Active ExploitationConfirmed and ongoing as of March 23
AttributionTeamPCP (DeadCatx3 / PCPcat / PersyPCP / ShellForce / CipherForce)
Incident ResponseSygnia engaged by Aqua Security
StatusNOT CONTAINED — attacker demonstrated continued access March 22

What Is Trivy, and Why Does It Matter?

Aqua Security and the Trivy Project

Aqua Security is an Israeli-American cloud security company founded in 2015. Their open-source project Trivy — a portmanteau of “Tri” (triage/scan) and “V” (vulnerabilities) — has become the most widely adopted open-source vulnerability scanner in the container and cloud-native ecosystem. The tool’s GitHub repository has over 24,000 stars, and the trivy-action GitHub Action is referenced in more than 10,000 workflow files across GitHub.

Trivy matters to this story for a specific reason: it sits inside CI/CD pipelines. Every time a developer pushes code, opens a pull request, or builds a container image, Trivy runs. It has access to the pipeline’s secrets, the runner’s filesystem, and the network. That position of trust — scanning code for vulnerabilities from inside the build process — is exactly what the attacker exploited.

What Trivy Scans

Trivy is a comprehensive security scanner that detects known vulnerabilities (CVEs), generates Software Bills of Materials (SBOMs), analyses licences, and scans for misconfigurations and exposed secrets. It operates across multiple scan targets:

TargetWhat Trivy ScansTypical CI/CD Usage
Container imagesOS packages (Alpine, Debian, RHEL, etc.) and language-specific dependencies (npm, pip, Maven, Go modules) baked into the imageScan every image before pushing to a registry
Filesystem/repositorySource code dependencies, lockfiles, IaC templates (Terraform, CloudFormation, Kubernetes manifests)Scan every PR for vulnerable dependencies
Kubernetes clustersRunning workloads, node configurations, RBAC policies, network policiesAudit live clusters on a schedule
AWS accountsIAM misconfigurations, S3 bucket policies, security group rulesCloud posture checks
SBOM filesIngest CycloneDX or SPDX SBOMs generated by other tools and scan them for known vulnerabilitiesSupply chain transparency

Trivy works by downloading vulnerability databases (maintained by Aqua from sources like NVD, vendor advisories, and GitHub Security Advisories), matching them against the packages and dependencies it discovers in the scan target, and reporting the results. The database is rebuilt daily and distributed as an OCI artifact via GitHub Container Registry.

A typical Trivy command looks like this:

# Scan a container image for vulnerabilities
trivy image –severity HIGH,CRITICAL nginx:1.25

# Scan a filesystem for vulnerable dependencies
trivy fs –scanners vuln,secret .

# Generate an SBOM in CycloneDX format
trivy image –format cyclonedx –output sbom.json myapp:latest

How the GitHub Actions Work — and Why They Were the Perfect Target

Trivy is distributed through multiple channels: direct binary download, Homebrew, apt/rpm packages, Docker images, and GitHub Actions. The GitHub Actions are where the attack surface lies.

aquasecurity/trivy-action is the primary integration point. When a developer adds it to a workflow, it:

  1. Calls aquasecurity/setup-trivy to download and install the Trivy binary on the runner
  2. Executes entrypoint.sh — the script that configures scan parameters and runs Trivy
  3. Produces scan results in the specified format (table, JSON, SARIF for GitHub Security tab)

A typical workflow reference looks like this:

name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@0.33.1
  with:
    image-ref: ‘myapp:${{ github.sha }}’
    format: ‘sarif’
    output: ‘trivy-results.sarif’
    severity: ‘CRITICAL,HIGH’

aquasecurity/setup-trivy handles the binary installation. It downloads a specific Trivy version, verifies it, and places it on the runner’s PATH. Workflows can call it directly for manual control over caching and version pinning.

name: Install Trivy
  uses: aquasecurity/setup-trivy@v0.2.0
  with:
    cache: true
    version: v0.69.3

The Trust Chain That Broke

Here is the critical point: when a workflow says uses: aquasecurity/trivy-action@0.33.1, GitHub resolves the tag 0.33.1 to a commit SHA at runtime. If that tag is force-pushed to point at a different commit, the workflow silently pulls the new code. The runner executes whatever entrypoint.sh contains — with full access to the pipeline’s secrets, the runner’s filesystem, network, and any credentials passed to the workflow.

The trust chain works like this:

Developer writes workflow → references trivy-action@0.33.1
                              ↓
GitHub resolves tag 0.33.1 → commit SHA (mutable pointer)
                              ↓
Runner downloads entrypoint.sh from that commit
                              ↓
entrypoint.sh executes with full runner permissions
  – Access to ${{ secrets.* }}
  – Access to GITHUB_TOKEN
  – Access to runner filesystem
  – Access to runner network
  – Access to /proc/[pid]/mem (on Linux with passwordless sudo)

In the legitimate case, entrypoint.sh configures scan parameters and runs Trivy. In the compromised case, entrypoint.sh runs a credential stealer for 105 lines and then runs the legitimate Trivy scan for the remaining 99 lines. The scan output looks normal. The pipeline passes. The developer never knows.

This is what makes CI/CD supply chain attacks uniquely dangerous compared to traditional application vulnerabilities: the malicious code runs with the privileges of the build system, not the application. It has access to every secret the pipeline can reach. And because the scanner itself is the payload, the very tool that is supposed to detect problems is the problem.

Over 10,000 workflow files on GitHub reference trivy-action. Every one of them trusts that the tag they pinned to still points to the code they reviewed when they set it up. That trust was broken on March 19 when TeamPCP rewrote 76 of 77 tags in under an hour.

Technical Anatomy

Root Cause: A Misconfigured Workflow, an Incomplete Rotation, and a Service Account That Bridges Two Orgs

The kill chain spans five weeks and at least three distinct attack phases. Each phase exploited a different consequence of the same root cause: a long-lived, over-privileged Personal Access Token for the aqua-bot service account (named ORG_REPO_TOKEN in GitHub Actions secrets) that had repo-scope — and likely admin-scope — access across the entire aquasecurity GitHub organisation. That token was used in at least 33 workflows.

Phase 1 — The Pwn Request (February 27-28)

Trivy’s repository had a pull_request_target workflow (apidiff.yaml) since October 2025. Boost Security’s poutine tool flagged it on November 29, 2025 — three months before exploitation. On February 27, attacker MegaGame10418 opened PR #10252 and closed it immediately. The workflow triggered anyway, checked out the attacker’s fork code with elevated permissions, and exfiltrated the aqua-bot PAT via a /proc/[pid]/mem memory dump technique to recv.hackmoltrepeat.com.

On February 28, an AI-powered bot called hackerbot-claw validated the stolen credentials by creating branches named 🤖🦞 on aquasecurity/trivy — the same emoji pattern used in the bot’s own PRs. The attacker then took over the repository: privatised it, renamed it, deleted releases between v0.27.0 and v0.69.1, and published a malicious VS Code extension to Open VSX.

Phase 2 — The Scanner Becomes the Weapon (March 19)

Aqua rotated credentials after the February incident. The rotation was not atomic. Subsequent investigation confirmed the attacker retained residual access via credentials missed during rotation.

Twenty days later, at 17:43:37 UTC on March 19, TeamPCP struck. Using the residual access, the attacker:

  1. Made imposter commits spoofing maintainer DmitriyLewen (on aquasecurity/trivy) and Guillermo Rauch / rauchg (on actions/checkout), with forged author names, emails, timestamps, and commit messages
  2. Pushed the v0.69.4 tag pointing to the poisoned commit. A v0.70.0 tag was briefly created first, then deleted — a botched first attempt that reveals the attacker initially tried a higher version before falling back to blend into the existing release series
  3. Compromised the aqua-bot service account and used it to push malicious workflows to tfsec, traceeshark, and trivy-action
  4. Exfiltrated additional Aqua credentials (GPG signing key, Docker Hub tokens, Twitter, Slack) to Cloudflare Tunnel C2 at plug-tab-protective-relay.trycloudflare.com
  5. Force-pushed 76 of 77 version tags in trivy-action to malicious commits containing the credential stealer
  6. Published 7 releases on setup-trivy in under 3 minutes (v0.1.0 through v0.2.5), rewriting every historical version’s release artifacts via direct API calls

The poisoned release pipeline ran the imposter checkout action, which downloaded backdoored Go source files and a linter config override from scan.aquasecurtiy[.]org (note the typosquat). GoReleaser built multi-platform binaries with –skip=validate to bypass build output validation. The binaries were pushed to Docker Hub, GHCR, ECR, and GitHub Releases.

Phase 3 — Continued Access and Internal Org Defacement (March 22)

On March 22, the attacker demonstrated that containment had failed again:

  • Published malicious Docker images v0.69.5 and v0.69.6 to Docker Hub, both containing the C2 domain hardcoded in the binary (confirmed by StepSecurity via strings analysis)
  • Defaced all 44 repositories in the aquasec-com GitHub organisation (Aqua’s internal org for proprietary code) in a 2-minute automated blitz — renaming every repo with a tpcp-docs- prefix and setting descriptions to “TeamPCP Owns Aqua Security”
  • Published internal Aqua repositories publicly on GitHub, exposing source code for Tracee, internal Trivy forks, CI/CD pipelines, Kubernetes operators, and team knowledge bases

Forensic analysis by OpenSourceMalware traced this to the Argon-DevOps-Mgt service account — a bot account that bridges both the public aquasecurity org and the private aquasec-com org. The attacker tested the stolen token 7 hours before the defacement by creating and deleting a ghost branch (update-plugin-links-v0.218.2) on aquasecurity/trivy-plugin-aqua.

Aqua confirmed on March 23 that the incident is “part of an ongoing and evolving attack, with the threat actor reestablishing access.” They engaged Sygnia for forensic investigation and are working to validate that all access paths have been identified.

Update 23-Mar-2026

Expanded v0.69.5/6 details: pushed WITHOUT corresponding GitHub releases, latest tag pointed to v0.69.6, Socket binary analysis confirming IOCs (payload.enc, tpcp.tar.gz), mirror.gcr.io serving cached copies after removal, third-party auto-rebuilt images as secondary blast radius, unauthorized repos in public aquasecurity org

Why it matters:

The Docker-only publish (no GitHub release) is a new escalation pattern — attacker bypassed the release pipeline entirely

The Imposter Commit Technique

The attack on the release pipeline is technically notable. The attacker did not modify the Trivy source code directly. Instead, they:

  1. Created a dangling commit on actions/checkout (SHA 70379aad) that replaced the real Node.js checkout action with a composite action downloading backdoored Go source files from the typosquatted C2
  2. Created a second dangling commit on aquasecurity/trivy (SHA 1885610c) that pinned actions/checkout to the imposter SHA — which looks like a security best practice — added –skip=validate to GoReleaser, and scattered cosmetic quote-style changes throughout the YAML to bury the real modifications in diff noise
  3. Both commits were unsigned and used forged author metadata

This exploits a subtle GitHub platform behaviour: a uses: owner/repo@<hash> reference does not verify that the hash belongs to the named repository. Due to Git’s fork object sharing, any commit from any fork is reachable by SHA. The build fetched backdoor Go source files from the C2, compiled them into the Trivy binary alongside the legitimate scanner, and published the result through official channels.

The Three-Stage Credential Stealer

The payload injected into trivy-action’s entrypoint.sh (204 lines) and setup-trivy’s action.yaml operates in three stages:

Stage 1 — Collection

On GitHub-hosted Linux runners, the malware uses passwordless sudo to dump Runner.Worker process memory via /proc/[pid]/mem, parsing readable memory regions and searching for {“value”:”<secret>”,”isSecret”:true} — the internal format GitHub Actions uses to store secrets in the .NET process heap. Only secrets explicitly referenced in the workflow (via ${{ secrets.* }}) are loaded into memory, but GITHUB_TOKEN is always available.

On self-hosted runners, a base64-encoded Python filesystem harvester (self-identified as “TeamPCP Cloud stealer”) sweeps 50+ paths:

CategoryTargets
SSH~/.ssh/id_rsa, id_ed25519, id_ecdsa, authorized_keys, known_hosts; /etc/ssh/ssh_host_*_key
AWS~/.aws/credentials, config, EC2 IMDS (169.254.169.254), ECS container creds (169.254.170.2)
GCP~/.config/gcloud/*, application_default_credentials.json
Azure~/.azure/, AZURE_ env vars
Kubernetes~/.kube/config, /etc/kubernetes/*.conf, service account tokens, kubectl get secrets -A -o json
Docker~/.docker/config.json, /kaniko/.docker/config.json
Database~/.pgpass, ~/.my.cnf, ~/.mongorc.js, redis.conf
CI/CD configsterraform.tfvars, terraform.tfstate, .gitlab-ci.yml, Jenkinsfile, ansible.cfg
Package managers~/.npmrc, ~/.vault-token, ~/.netrc
TLS private keys.key, .pem, .p12, .pfx; /etc/ssl/private/, /etc/letsencrypt/
Crypto walletsBitcoin, Ethereum, Solana keypairs, Cardano signing keys, Ledger files
Environment files.env, .env.local, .env.production across /opt, /srv, /var/www, /app, /data, /tmp

Stage 2 — Encryption

Collected data is encrypted using AES-256-CBC (key derived via PBKDF2 from 32 random bytes). The session key is wrapped with an embedded RSA-4096 public key using OAEP padding. Both files are bundled into tpcp.tar.gz. Only the RSA private key holder can decrypt.

Stage 3 — Exfiltration

Primary: HTTPS POST to scan.aquasecurtiy[.]org (45.148.10.212) with header X-Filename: tpcp.tar.gz.

Fallback: If the C2 returns non-2xx and INPUT_GITHUB_PAT is available, the malware creates a public repository called tpcp-docs on the victim’s own GitHub account and uploads the bundle as a release asset with a timestamped tag. The data sits on GitHub’s own infrastructure — unlikely to be blocked by corporate firewalls.

The backdoored binary (v0.69.4, v0.69.5, v0.69.6)

The compromised Trivy binaries run the legitimate scanner in parallel with a malicious process. On developer machines (detected by checking GITHUB_ACTIONS != “true”), the malware writes a Python dropper to ~/.config/systemd/user/sysmon.py. After a 5-minute sleep, it polls an ICP canister (tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io) every ~50 minutes. The canister returns a URL pointing to the next-stage payload. A youtube.com URL acts as a kill switch (dormant state). As of March 22, the canister was actively serving kamikaze.sh, an iteratively developed payload, before being taken offline for policy violations.

Core Behaviours

BehaviourDetail
Process memory dumpingReads /proc/[pid]/mem of Runner.Worker to extract GitHub Actions secrets
Filesystem credential sweep50+ paths across SSH, cloud, K8s, Docker, databases, crypto, CI/CD configs
Hybrid encryptionAES-256-CBC + RSA-4096 wrapping — only attacker’s private key can decrypt
Dual exfiltrationPrimary C2 (typosquat domain) + fallback (victim’s own GitHub account)
Imposter commitsForged author metadata, dangling commits not attached to any branch
Tag poisoningForce-pushed existing version tags — no notifications, no diff, no alerts
Counter-incident responseDeleted disclosure discussion, flooded replacement with 47 spam bots in 12 seconds
Persistencesystemd user service (pgmon/sysmon.py) on developer machines, ICP canister dead-drop C2
Self-propagating wormCanisterWorm harvests npm tokens during postinstall, infects downstream packages automatically
Org-level takeoverDefaced 44 internal repos via compromised service account bridging two orgs

CanisterWorm: The npm Cascade

Stolen npm tokens from the Trivy compromise triggered CanisterWorm, a self-propagating worm detected by Aikido Security on March 20 at 20:45 UTC. The worm uses an ICP (Internet Computer Protocol) canister as a decentralised dead-drop resolver for C2 — the first documented abuse of this technique.

Compromised packages: 28 in @emilgroup, 16 in @opengov, plus @teale.io/eslint-config, @airtm/uuid-base32, @pypestream/floating-ui-dom.

Three-stage architecture: 1. Node.js postinstall hook decodes a Python backdoor, writes it to ~/.local/share/pgmon/service.py, creates a systemd user service with Restart=always 2. Python backdoor polls the ICP canister every ~50 minutes; downloads and executes whatever URL the canister returns 3. deploy.js worm enumerates every package a stolen npm token can publish, bumps patch versions, preserves the original README, and publishes with –tag latest

A self-propagating variant (Wave 3) adds findNpmTokens() during postinstall — harvesting tokens from ~/.npmrc, environment variables, and npm config, then spawning the worm as a detached process. Every infected developer or CI pipeline becomes a propagation vector.

The worm appears to be entirely “vibe-coded” using an AI tool — no obfuscation, emoji-prefixed logging, self-explanatory variable names. Aikido Security reported that the attacker left a message in the source code addressing their researcher by name.

As of March 22, TeamPCP has also deployed Kubernetes wipers targeting infrastructure in Iran, as reported by Aikido Security.

Affected Versions

ComponentVulnerableSafe VersionExposure Window (UTC)Duration
trivy-actionAll old tags 0.0.1–0.34.2 (no v prefix)v0.35.0 (SHA: 57a97c7e). New v-prefixed tags (v0.0.1–v0.34.2) point to original commits.Mar 19 ~17:43 to Mar 20 ~05:40~12 hours
setup-trivyAll versions v0.1.0–v0.2.5v0.2.6Mar 19 ~17:43 to ~21:44~4 hours
trivy binaryv0.69.4v0.69.2, v0.69.3Mar 19 18:22 to ~21:42~3 hours
trivy Docker Hubv0.69.4, v0.69.5, v0.69.6v0.69.3 or earlier; images by digestv0.69.4: Mar 19; v0.69.5/6: Mar 22 ~16:00Ongoing
trivy GHCRv0.69.4v0.69.3Mar 19 ~18:25 to removal~3 hours
trivy ECRv0.69.4v0.69.3Mar 19 ~18:25 to removal~3 hours
HomebrewPicked up v0.69.4 (source build, binary NOT backdoored)Rolled back to v0.69.3N/ANot backdoored
apt/rpmNot affectedN/AN/AN/A
npm packages47+ packages (@emilgroup, @opengov, @teale.io, etc.)Roll back to pre-Mar 20 versionsMar 20 20:45 onwardsOngoing
aquasec-com orgAll 44 repos defaced and exposedN/A — internal remediation requiredMar 22 20:31–20:32Ongoing

Critical note on tag naming: Old version tags without a v prefix (0.0.1–0.34.2) should be considered compromised. New tags have been published with a v prefix (v0.0.1–v0.34.2) pointing to the original legitimate commits. Pin to the full SHA hash regardless.

Compromised credentials to assume exposed: – GITHUB_TOKEN (always available) – Any secret referenced via ${{ secrets.* }} in the workflow – Cloud provider credentials (AWS, GCP, Azure) – Docker registry tokens – SSH keys and Kubernetes tokens – npm publish tokens (treat as actively weaponised) – The Aqua Security GPG signing key (ID E9D0A3616276FA6C, in use since 2019, written to disk in cleartext during the release build — must be considered compromised)

Discovery and Disclosure Timeline of Trivy Supply Chain attack

DateEvent
October 2025Vulnerable pull_request_target workflow (apidiff.yaml) added to Trivy repo
November 29, 2025Boost Security’s poutine tool flags the workflow — no action taken
February 20, 2026hackerbot-claw account created on GitHub
February 27, 2026MegaGame10418 opens and closes PR #10252, triggering workflow exfiltration
February 28, 2026hackerbot-claw validates stolen aqua-bot PAT (🤖🦞 branches). Trivy repo privatised, releases deleted, malicious VS Code extension pushed
February 28, 06:08 UTCCredential rotation begins (vuln-list-update failures observed through March 1)
March 1, 2026Aqua Security discloses incident in Discussion #10265, releases v0.69.2
March 3, 2026Trivy v0.69.3 released (current safe version)
March 19, 17:43 UTCTeamPCP pushes v0.69.4 tag via poisoned commit. v0.70.0 tag briefly created then deleted (botched first attempt)
March 19, 17:51 UTCaqua-bot deletes v0.70.0 tag
March 19, 18:25 UTCPoisoned release published — backdoored binaries pushed to Docker Hub, GHCR, ECR, GitHub Releases
March 19, ~18:45 UTC76 trivy-action tags and 7 setup-trivy tags force-pushed to malicious commits
March 19, ~19:15 UTCFirst detection (Paul McCarty). Socket generates 182 threat feed entries.
March 19, 21:07 UTCTrivy maintainer nikpivkin begins deleting compromised setup-trivy tags
March 19, 21:43 UTCClean setup-trivy v0.2.6 published
March 19, 23:05 UTCHomebrew emergency downgrade PR filed by William Woodruff (Trail of Bits)
March 19, 23:13 UTCTrivy maintainer knqyf263 deletes v0.69.4 tag
March 19, 23:56 UTCbored-engineer confirms compromise, shares IOCs from deleted discussion
March 20, 00:01 UTCSpam bots flood Discussion #10420 (47 accounts, 12-second window)
March 20, ~05:40 UTCMalicious trivy-action artifacts removed
March 20, 20:45 UTCCanisterWorm Wave 1 detected by Aikido — 28 @emilgroup packages compromised
March 20, 21:16 UTCCanisterWorm Wave 3 — self-propagating variant with findNpmTokens()
March 22, 13:24 UTCArgon-DevOps-Mgt creates/deletes ghost branch on trivy-plugin-aqua (token test)
March 22, ~16:00 UTCBackdoored trivy Docker images v0.69.5 and v0.69.6 published to Docker Hub
March 22, 20:31 UTCAll 44 aquasec-com repos defaced in 2-minute automated blitz
March 22, 21:31 UTCICP canister made “Unavailable Due to Policy Violation”
March 23, 02:00 UTCAqua confirms “additional suspicious activity” on March 22, engages Sygnia, confirms ongoing attack
March 23 , 09:00 UTC“no corresponding GitHub releases”, “latest tag pointed to v0.69.6″, “Socket confirms IOCs in binaries”. Added new March 22–23 entry for mirror caching persistence.

Determine If You’re Affected by Trivy Supply Chain attack

Exposure check (do all of these)

  1. Search workflow files for Trivy references:

grep -r “aquasecurity/trivy-action” .github/workflows/
grep -r “aquasecurity/setup-trivy” .github/workflows/

  1. Check if any workflow used a version tag (not SHA) during any exposure window. Review the “Run Trivy” step of trivy-action and the “Setup environment” step of setup-trivy in your workflow run logs.
  2. Check for the backdoored binary. Search container registries, artifact caches, and CI build logs for trivy v0.69.4, v0.69.5, or v0.69.6.

docker images | grep trivy | grep -E “0.69.[456]”

  1. Check for exfiltration artifacts. Search your GitHub org for repositories named tpcp-docs:

gh repo list YOUR_ORG –json name -q ‘.[].name’ | grep tpcp-docs

  1. Check self-hosted runners and developer machines for persistence:

ls -la ~/.config/sysmon.py 2>/dev/null
ls -la ~/.config/systemd/user/pgmon.service 2>/dev/null
ls -la ~/.local/share/pgmon/service.py 2>/dev/null
ls -la /tmp/pglog /tmp/.pg_state 2>/dev/null
systemctl –user status pgmon.service 2>/dev/null
systemctl –user status sysmon 2>/dev/null

  1. Check network logs for C2 indicators:

scan.aquasecurtiy[.]org
45.148.10.212
plug-tab-protective-relay.trycloudflare.com
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io
championships-peoples-point-cassette.trycloudflare.com
investigation-launches-hearings-copying.trycloudflare.com
souls-entire-defined-routes.trycloudflare.com

  1. Check npm lockfiles for compromised packages from @emilgroup, @opengov, @teale.io/eslint-config, @airtm/uuid-base32, or @pypestream/floating-ui-dom with post-March 20 patch bumps.
  2. Run StepSecurity’s trivy-compromise-scanner for automated log auditing across repos or entire organisations: https://github.com/step-security/trivy-compromise-scanner

Which secrets were exposed?

Only secrets explicitly referenced in the workflow (via ${{ secrets.* }}) are loaded into Runner.Worker memory. GITHUB_TOKEN is always accessible. If your workflow uses secrets: inherit for reusable workflows, only secrets actually referenced in the called workflow are extractable — not all org/repo secrets.

That said, treat every credential accessible to the affected pipeline as compromised. Lateral movement is expected: attackers have been observed creating new workflows in new branches specifically to exfiltrate secrets from additional repositories after gaining initial access.

Temporary Protections

If you cannot complete full remediation immediately:

  1. Pin trivy-action to the safe SHA:

# SAFE — immutable commit reference
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1
# DO NOT USE version tags — even v-prefixed tags, until you verify the SHA

  1. Pin setup-trivy to v0.2.6 (the only uncompromised version)
  2. Block all IOC domains and IPs at the network perimeter — see the full IOC table below
  3. Restrict outbound network access from CI/CD runners to known-good destinations. If using StepSecurity Harden-Runner, enable block mode to prevent connections to unknown domains.
  4. Enable GitHub’s required workflows feature to enforce SHA-pinned action references org-wide
  5. Monitor GitHub audit logs for repository creation events matching the tpcp-docs pattern
  6. Stop pulling trivy Docker images by tag — use image digests until the situation stabilises

How TeamPCP Exploits This — and What Comes Next

The credential harvest from this campaign gives TeamPCP an expanding attack surface:

Immediate exploitation (already observed): – Stolen npm tokens weaponised via CanisterWorm to infect 47+ downstream packages – Stolen Aqua credentials used to publish additional backdoored images (v0.69.5, v0.69.6) – Stolen service account tokens used to deface internal org (44 repos exposed) – Counter-IR tactics: deleting disclosure threads, flooding discussions with spam bots – Kubernetes wipers targeting infrastructure in Iran

Probable next steps (based on TeamPCP’s documented TTPs): – Stolen cloud credentials (AWS/GCP/Azure) used for cryptomining, data theft, or ransomware staging – Compromised SSH keys used for lateral movement into production environments – The GPG signing key (E9D0A3616276FA6C) could be used to sign malicious RPM packages that appear to come from Aqua Security – Stolen Docker Hub credentials could be used to publish further backdoored images under the official aquasec namespace – The ICP canister C2 can be re-armed at any time — even though the current one was taken down, the attacker can deploy a new canister. Decentralised C2 infrastructure is resilient to takedowns by design. – Any organisation whose secrets were exfiltrated from a CI/CD pipeline now faces secondary compromise risk: the attacker has their cloud keys, their registry tokens, their npm publish credentials

What makes this campaign structurally different: – The attacker weaponised a security tool — the very scanner organisations rely on to find vulnerabilities became the credential stealer – Mutable Git tags are a platform-level weakness, not a misconfiguration — GitHub does not notify anyone when a tag is force-pushed – The ICP canister dead-drop is a new C2 pattern that is resistant to traditional domain takedowns – The self-propagating CanisterWorm turns each compromised developer into an unwitting distribution vector – Three compromises in under a month with the attacker re-establishing access each time demonstrates that credential rotation is failing at Aqua

Update March 23 2026

Docker Hub bypass (no release pipeline), latest tag redirection, mirror caching extending attack shelf life, third-party auto-rebuild as silent propagation. Added to “structurally different”: Docker tags share Git tags’ mutability weakness, mirror caching extends shelf life.

Why it matters: These are active exploitation paths, not theoretical — the latest tag redirection and mirror caching are confirmed

Remediation Guidance

Immediate Actions

  1. Pin trivy-action to SHA 57a97c7e7821a5776cebc9bb87c984fa69cba8f1 — do not use any version tag
  2. Pin setup-trivy to v0.2.6
  3. Ensure trivy binary is v0.69.2 or v0.69.3 — remove v0.69.4, v0.69.5, v0.69.6 from all registries and caches
  4. Rotate ALL pipeline secrets if any workflow ran a compromised component during any exposure window. This includes: GitHub tokens, cloud credentials, SSH keys, Docker registry tokens, Kubernetes tokens, database passwords, npm publish tokens
  5. Block all IOC domains and IPs at network perimeter and in CI/CD runner egress rules
  6. Search for tpcp-docs repositories in your GitHub org — if found, assume full credential exfiltration
  7. Kill and remove persistence mechanisms on self-hosted runners and dev machines:

systemctl –user stop pgmon.service sysmon 2>/dev/null
systemctl –user disable pgmon.service sysmon 2>/dev/null
rm -f ~/.config/systemd/user/pgmon.service
rm -rf ~/.local/share/pgmon/
rm -f ~/.config/sysmon.py
rm -f /tmp/pglog /tmp/.pg_state
systemctl –user daemon-reload

  1. Audit npm dependencies for compromised @emilgroup, @opengov, @teale.io, @airtm, @pypestream packages — roll back to pre-March 20 versions

Long-Term Hardening

  • Pin ALL GitHub Actions to full SHA hashes — automate with zizmor, pinact, StepSecurity secure-repo, or Renovate’s pinGitHubActionDigests
  • Audit every pull_request_target workflow — if it checks out PR head code, it is a Pwn Request waiting to happen
  • Minimise token permissions — replace org-scoped PATs with fine-grained tokens scoped to individual repos
  • Enforce commit signing on release workflows — both imposter commits in this attack were unsigned
  • Enable immutable releases on all repositories publishing GitHub Actions
  • Restrict outbound network from CI/CD runners to allowlisted destinations
  • Use StepSecurity Harden-Runner or equivalent for runtime anomaly detection on GitHub Actions runners
  • Monitor for secondary compromise — attackers with stolen credentials are observed creating new workflows in new branches to exfiltrate additional secrets. This is not a one-time rotation.
  • Added 23 March: Docker digest pinning (not tag), registry mirror audit/eviction policies, trusted publishing for downstream package maintainers

Detection Guidance

IOCs — Network

IndicatorTypeAction
scan.aquasecurtiy[.]orgExfiltration domain (typosquat)Block at perimeter, hunt DNS logs
45.148.10.212Exfiltration IP (TECHOFF SRV LIMITED, Amsterdam)Block at firewall, hunt NetFlow
plug-tab-protective-relay.trycloudflare.comCloudflare Tunnel C2Block, search DNS logs
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.ioICP canister C2 dead-dropBlock egress to icp0.io — standard domain takedowns do not apply
championships-peoples-point-cassette.trycloudflare.comSecondary Cloudflare C2Block
investigation-launches-hearings-copying.trycloudflare.comSecondary Cloudflare C2Block
souls-entire-defined-routes.trycloudflare.comSecondary Cloudflare C2Block
recv.hackmoltrepeat.comInitial C2 (February breach)Block

IOCs — File Hashes

Hash (SHA256)Description
18a24f83e807479438dcab7a1804c51a00dafc1d526698a66e0640d1e5dd671aMalicious entrypoint.sh
822dd269ec10459572dfaaefe163dae693c344249a0161953f0d5cdd110bd2a0Compromised trivy v0.69.4 Linux-64bit
6328a34b26a63423b555a61f89a6a0525a534e9c88584c815d937910f1ddd538Compromised trivy v0.69.4 macOS-ARM64
0880819ef821cff918960a39c1c1aada55a5593c61c608ea9215da858a86e349Compromised trivy v0.69.4 Windows-64bit
887e1f5b5b50162a60bd03b66269e0ae545d0aef0583c1c5b00972152ad7e073Compromised trivy v0.69.4 FreeBSD-64bit
3350da5e45f99ec86eec5cb87efe84241d82a019822e4270facb818519778d12Poisoned v0.69.4.tar.gz
3ca5fa62932273dd7eef3b6ec762625da42304ebb8f13e4be9fdd61545ca1773Known-good v0.69.3.tar.gz

IOCs — Filesystem

PathDescription
~/.config/sysmon.pyTrivy binary dropper
~/.config/systemd/user/pgmon.serviceCanisterWorm persistence
~/.local/share/pgmon/service.pyCanisterWorm backdoor
/tmp/pglogCanisterWorm payload
/tmp/.pg_stateCanisterWorm state tracker

IOCs — GitHub

IndicatorDescription
Repository named tpcp-docsFallback exfiltration via victim’s own GitHub account
Repo prefix tpcp-docs-aquasec-com org defacement pattern
Description “TeamPCP Owns Aqua Security”Defacement signature

Forgery Detection Indicators

  • Unsigned commits on releases that were previously GPG-signed by GitHub’s web-flow
  • Impossible timestamps: commit dates from 2021-2024 with parent commits from March 2026
  • Single-file modifications: each malicious trivy-action commit only modifies entrypoint.sh (tree is master HEAD)
  • “0 commits to master since this release” on GitHub release pages for tags that should show hundreds

Phoenix Security Recommendations

The Trivy compromise is a case study in why vulnerability management cannot stop at scanning known CVEs. This attack had no CVE, no CVSS score, no NVD entry. The scanner itself was the attack vector. Traditional security tooling would not have flagged it.

Attack surface management: Phoenix identifies CI/CD pipelines running compromised components and maps whether references use mutable tags or immutable SHAs. When 10,000+ workflows reference a single action, you need automated discovery — not a grep.

Reachability analysis: Not every pipeline that references trivy-action actually executed during the exposure windows. Phoenix maps which instances ran compromised code versus which merely declared the action in a workflow file. This is the difference between rotating secrets for 10,000 repos and rotating secrets for the 45 that StepSecurity confirmed were actually affected.

Contextual deduplication: Organisations using Trivy across dozens of repositories get a single prioritised backlog rather than duplicate alerts per scanner per repo. One campaign. One response track.

Remediation campaigns: Create a campaign in Phoenix to track the full response — SHA migration, secret rotation per repo, IOC blocking confirmations, persistence removal on self-hosted runners — with ownership assigned per team.

Ownership attribution: In an organisation with hundreds of repositories using trivy-action, knowing who owns each pipeline is the difference between a coordinated response and weeks of email chains. Phoenix maps every affected workflow to the team that owns it.

Phoenix Security correlates compromised components with runtime workloads, identifies exposed pipelines via attack surface management, and assigns remediation ownership — converting a supply chain campaign into a measurable, owned response.

For more on CI/CD supply chain defence, see our analysis of the tj-actions compromise from 2025: https://phoenix.security/tj-actions-compromise/

References

  1. Aqua Security — “Update: Ongoing Investigation and Additional Activity” (March 23, 2026)
  2. GitHub Security Advisory — GHSA-cxm3-wv7p-598c
  3. Wiz Research — “Trivy Compromised: Everything You Need to Know”
  4. Boost Security — “20 Days Later: Trivy Compromise, Act II”
  5. Socket Security — “Trivy Under Attack Again: Widespread GitHub Actions Tag Compromise”
  6. CrowdStrike — “From Scanner to Stealer: Inside the trivy-action Supply Chain Compromise.”
  7. StepSecurity — “Trivy Compromised a Second Time”
  8. Aikido Security — “TeamPCP deploys CanisterWorm on NPM following Trivy compromise.”
  9. OpenSourceMalware — “TeamPCP Defaces Aqua Security’s Internal GitHub Org — 44 Repos Exposed”
  10. Socket Security — “CanisterWorm: npm Publisher Compromise Deploys Backdoor.”
  11. aquasecurity/trivy-action Release v0.35.0

How Phoenix Security Fixes What Actually Matters

Your team doesn’t have a finding problem. They have a fixing problem.

Most platforms hand you a list. Phoenix hands you a plan — ranked by real risk, mapped to the team that owns it, with a clear path to close it.

What remediation looks like with Phoenix:

  • One backlog, not five. Findings from SAST, SCA, containers, and cloud — deduplicated, correlated, and surfaced in a single prioritized queue. No more reconciling lists across tools.
  • Ownership that sticks. Team attribution and inheritance mean the right ticket goes to the right engineer, first time. No routing, no guessing, no back-and-forth.
  • Campaigns that move the needle. Group related findings into targeted remediation campaigns. Track progress, measure closure rates, and report real reduction — not raw counts.
  • AI that does the legwork, not the deciding. Phoenix’s Remediator agent drafts fixes, creates tickets, and opens PRs. Your team reviews, approves, and merges. Every fix is traceable.

Phoenix Security changes the game.

The results are clear:

  • Bazaarvoice saved $6.3M in developer time and for teams removed critical in the first weeks of adoption
  • ClearBank cut critical container vulnerabilities by 96–99% and reclaimed 4 hours per engineer per week.
  • IAS saved an equivalent of 1.5M in development hours and reduced SCA-to-container noise by 82.4%
  • Optimizely has been able to act on vulnerabilities sitting on the backlog.

The pattern is the same every time: teams that move from find and report to analyze and fix close more risk with less effort.

The results are clear:

  • Bazaarvoice saved $6.3M in developer time and for teams removed critical in the first weeks of adoption
  • ClearBank cut critical container vulnerabilities by 96–99% and reclaimed 4 hours per engineer per week.
  • IAS saved an equivalent of 1.5M in development hours and reduced SCA-to-container noise by 82.4%
  • Optimizely has been able to act on vulnerabilities sitting on the backlog.

👉 Book a demo today

Or learn how Phoenix Security slashed millions in wasted dev time for fintech, retail, and adtech leaders.

Fix with remediaiton don’t chase ghost vulnerabilities

Francesco is an internationally renowned public speaker, with multiple interviews in high-profile publications (eg. Forbes), and an author of numerous books and articles, who utilises his platform to evangelize the importance of Cloud security and cutting-edge technologies on a global scale.

Discuss this blog with our community on Slack

Join our AppSec Phoenix community on Slack to discuss this blog and other news with our professional security team

From our Blog

TeamPCP turned Trivy into a credential stealer by force-pushing 75 version tags to malicious commits — causing thousands of CI/CD pipelines to silently execute attacker code.
Francesco Cipollone
Phoenix Security announced the general availability of its AI-powered Remediation Engine, enabling agentless container vulnerability remediation aligned with CTEM principles. By correlating container lineage to build files, the platform reduces SCA noise by up to 91% and generates precise remediation actions engineers and AI agents can execute instantly.
Francesco Cipollone
Phoenix Security approaches vulnerability management as a remediation engineering problem. By combining reachability analysis, contextual deduplication, and minimal-impact upgrades, Phoenix transforms hundreds of findings into a small set of changes engineers can actually ship.
Francesco Cipollone
The 2026 Latio Application Security Market Report signals a decisive shift from traditional ASPM to Continuous Threat Exposure Management (CTEM), redefining how enterprises reduce exposure, validate runtime risk, and drive remediation at scale.
Francesco Cipollone
Contents
Derek

Derek Fisher

Head of product security at a global fintech

Derek Fisher – Head of product security at a global fintech. Speaker, instructor, and author in application security.

Derek is an award winning author of a children’s book series in cybersecurity as well as the author of “The Application Security Handbook.” He is a university instructor at Temple University where he teaches software development security to undergraduate and graduate students. He is a speaker on topics in the cybersecurity space and has led teams, large and small, at organizations in the healthcare and financial industries. He has built and matured information security teams as well as implemented organizational information security strategies to reduce the organizations risk.

Derek got his start in the hardware engineering space where he learned about designing circuits and building assemblies for commercial and military applications. He later pursued a computer science degree in order to advance a career in software development. This is where Derek was introduced to cybersecurity and soon caught the bug. He found a mentor to help him grow in cybersecurity and then pursued a graduate degree in the subject.

Since then Derek has worked in the product security space as an architect and leader. He has led teams to deliver more secure software in organizations from multiple industries. His focus has been to raise the security awareness of the engineering organization while maintaining a practice of secure code development, delivery, and operations.

In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

Jeevan Singh

Jeevan Singh

Founder of Manicode Security

Jeevan Singh is the Director of Security Engineering at Rippling, with a background spanning various Engineering and Security leadership roles over the course of his career. He’s dedicated to the integration of security practices into software development, working to create a security-aware culture within organizations and imparting security best practices to the team.
In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

James

James Berthoty

Founder of Latio Tech

James Berthoty has over ten years of experience across product and security domains. He founded Latio Tech to help companies find the right security tools for their needs without vendor bias.

christophe

Christophe Parisel

Senior Cloud Security Architect

Senior Cloud Security Architect

Chris

Chris Romeo

Co-Founder
Security Journey

Chris Romeo is a leading voice and thinker in application security, threat modeling, and security champions and the CEO of Devici and General Partner at Kerr Ventures. Chris hosts the award-winning “Application Security Podcast,” “The Security Table,” and “The Threat Modeling Podcast” and is a highly rated industry speaker and trainer, featured at the RSA Conference, the AppSec Village @ DefCon, OWASP Global AppSec, ISC2 Security Congress, InfoSec World and All Day DevOps. Chris founded Security Journey, a security education company, leading to an exit in 2022. Chris was the Chief Security Advocate at Cisco, spreading security knowledge through education and champion programs. Chris has twenty-six years of security experience, holding positions across the gamut, including application security, security engineering, incident response, and various Executive roles. Chris holds the CISSP and CSSLP certifications.

jim

Jim Manico

Founder of Manicode Security

Jim Manico is the founder of Manicode Security, where he trains software developers on secure coding and security engineering. Jim is also the founder of Brakeman Security, Inc. and an investor/advisor for Signal Sciences. He is the author of Iron-Clad Java: Building Secure Web Applications (McGraw-Hill), a frequent speaker on secure software practices, and a member of the JavaOne Rockstar speaker community. Jim is also a volunteer for and former board member of the OWASP foundation.

Join our Mailing list!

Get all the latest news, exclusive deals, and feature updates.

The IKIGAI concept
x  Powerful Protection for WordPress, from Shield Security PRO
This Site Is Protected By
Shield Security PRO