Here's my take: compromising Trivy isn't compromising a peripheral security tool. It's compromising the vulnerability scanner running inside CI/CD pipelines across thousands of organizations β with elevated privileges, access to private container registries, and authentication tokens in plain sight. That's exactly why TeamPCP chose it.
No CVE assigned yet β the investigation is ongoing β but the attack vector is documented. TeamPCP obtained npm publishing credentials for the Trivy project through a targeted phishing campaign against an Aqua Security maintainer. With those credentials, they published trojanized versions of @aquasecurity/trivy-node β the npm wrapper for Trivy β embedding the CanisterWorm dropper in the postinstall hook. The first malicious publish appeared on March 3, 2026. Three weeks passed without that package appearing on any threat intelligence feed.
That's not the work of an ordinary threat actor.
Trivy as Vector: What TeamPCP Actually Compromised
Trivy is the most widely deployed container vulnerability scanner in CI/CD pipelines β over 21 million monthly npm downloads, with documented presence in GitHub Actions, GitLab CI, and ArgoCD workflows. Its position in the pipeline is strategic: it runs with elevated privileges, has access to private container registries, and produces vulnerability manifests consumed by downstream tooling. A scanner that can't scan isn't doing its job β which is precisely why security teams configure it with the permissions it needs to access everything.
TeamPCP didn't compromise the Trivy application itself β the official binary and Aqua Security's Docker images remain clean per published hashes. They compromised @aquasecurity/trivy-node, the JavaScript wrapper teams use to invoke Trivy from Node.js pipelines. A technical distinction that most teams reviewing their initial SBOM failed to verify with sufficient granularity.
| Trivy Component | Affected Versions | Infection Mechanism |
|---|---|---|
trivy binary (GitHub Releases) |
None | N/A β not compromised |
Docker image aquasec/trivy |
None | N/A β not compromised |
npm @aquasecurity/trivy-node |
v0.9.4 β v0.9.7 | Dropper in postinstall hook |
The postinstall hook vector is deliberate: this npm lifecycle script executes automatically during npm install, before the developer touches the package. No explicit invocation of compromised code required. If that version range appears in your package-lock.json, the dropper already ran in every environment where you've installed dependencies.
CanisterWorm: The Worm That Spreads Itself
What separates CanisterWorm from a conventional supply chain attack is autonomous self-propagation. TeamPCP doesn't manually publish to each infected package β the worm does it for them.
The mechanism operates in three phases after initial infection:
- Token reconnaissance: scans
~/.npmrc, local.npmrc, and environment variables for npm tokens with publish permissions. In CI/CD environments, these tokens are typically available as environment variables to enable automated releases. - Publishable package inventory: queries the npm Registry API to identify which packages are associated with the discovered tokens and where those tokens have write permissions.
- Trojanized autopublish: publishes patch-bump versions (+0.0.1) of every identified package, embedding the CanisterWorm dropper in the postinstall hook. A patch bump in standard semver automatically triggers an update in any project using
^x.y.zor~x.y.zranges.
Twenty-one days. Sixty-six confirmed compromised packages. npm Security Team has over 80 additional suspicious packages under active analysis.
The mechanism works because of a pervasive operational pattern: npm publish tokens in CI/CD environments with no MFA and overly broad scope. Socket Security's January 2026 analysis found that 23% of npm packages with over 100,000 weekly downloads have CI/CD publish tokens without granular per-package scoping.
Blockchain C2: Why Your Firewall Won't Help Here
The command-and-control channel is where CanisterWorm presents its most operationally inconvenient innovation for defenders.
Instructions don't arrive over conventional IPs or domains. TeamPCP encodes commands in the input data field of Ethereum blockchain transactions to a fixed wallet address. The worm's C2 module polls that wallet through public RPC nodes β Infura, Alchemy, QuickNode β every 15 minutes. When TeamPCP wants to activate the wiper, exfiltrate data, or update the payload, they construct a transaction with the command in hexadecimal. Cost per instruction: under $0.01 in gas fees.
The defensive implications are concrete:
- IP blocking is not viable: Infura and Alchemy RPC nodes serve legitimate traffic for thousands of Web3 applications, developer SDKs, and internal tooling. Blocking them breaks legitimate workflows in most organizations.
- HTTPS traffic is indistinguishable: RPC requests use standard HTTPS with the same User-Agent as any other external API call. There's no network signature to block without massive false positives.
- C2 infrastructure is immutable: unlike domains that can be seized or expire, the Ethereum wallet is permanent. TeamPCP can go dark for months and resume control at any point without registering a single new domain.
I should be clear: my technical assessment is based on published analyses from Socket Security and ReversingLabs through March 22, 2026. I haven't had access to Aqua Security's complete forensic report, which was pending publication at press time.
The Kubernetes Wiper and the Iran Signature
The second-stage payload is where this escalates from supply chain attack to destructive incident with geopolitical overtones.
When TeamPCP activates the wiper module through the blockchain C2 channel, CanisterWorm executes a destruction sequence against the compromised Kubernetes cluster: kubectl delete namespace --all, followed by direct corruption of etcd if the port is accessible from the pod, and deletion of all PersistentVolumeClaims before they can be cleanly released.
Complete cluster deletion.
CrowdStrike Threat Intelligence's forensic analysis of three confirmed incidents revealed an anomaly: the wiper module includes an automatic activation check independent of the C2. If the OS locale is set to fa_IR (Farsi/Persian) or if the outbound IP resolves to ranges assigned to Iranian telecom providers β Irancell, ASIS, Pishgaman, among others β the wiper module activates without waiting for an explicit blockchain instruction.
This makes CanisterWorm a dual-purpose tool: espionage and data exfiltration everywhere else, with automatic destructive activation on Iranian infrastructure. A pattern consistent with nation-state-aligned threat actors β though definitive public attribution to a specific state had not been confirmed at publication time.
For context on how a single access vector into security infrastructure can translate to full network compromise, the analysis of CVE-2026-20131 in Cisco FMC describes a structurally similar escalation pattern.
Immediate Actions β No Ambiguity
Let's be real: the response here is not complicated, but it requires doing it now, not at next quarter's security review.
- Audit dependencies: check whether
@aquasecurity/trivy-nodeversions v0.9.4βv0.9.7 appear directly or transitively inpackage-lock.jsonoryarn.lock. The minimum safe version is v0.9.8. - Revoke all exposed npm tokens: any npm token present in
.npmrcor as an environment variable in environments where the compromised package may have run should be treated as compromised. Generate new tokens with per-package scoping and minimum permissions. - Audit your npm publish history: if you find unauthorized patch bumps on your packages between March 3 and March 22, 2026, the package is infected. Contact npm Security Team and publish a rollback version.
- Review outbound access to Ethereum RPC nodes from your CI/CD pipelines: if you're not legitimately using Infura or Alchemy, block their IPs in your runner security groups. It won't fix already-compromised installs, but it cuts active C2 communication.
- Enable MFA and granular scoping on npm publish tokens: it's unacceptable that in 2026, tokens for packages with millions of weekly downloads are protected by a password alone.
I've seen this movie before β the event-stream incident in 2018 showed that targeting npm package maintainers works. What's different now is the C2 infrastructure, the autonomous propagation mechanism, and the geopolitical payload embedded in the wiper. The elephant in the room is that the npm ecosystem's trust model fundamentally cannot prevent this without structural changes to how publish permissions are scoped and audited. Organizations running Node.js pipelines and Kubernetes in production need to act on this now, not when the official CVE is assigned.




