CI/CDnpmopen-source-securitySupply Chain

Your Vulnerability Scanner Just Became the Vulnerability

4 min read
Share

There's a particular kind of irony when the tool you trust to find security holes becomes the security hole. Trivy - Aqua Security's open-source vulnerability scanner, the one sitting in probably a third of the CI/CD pipelines I've audited - got supply-chain compromised. Not once. Twice in a month. And the second time, the attackers got creative.

What happened the first time

The initial compromise was almost elegant in its simplicity. A bot called hackerbot-claw exploited a pull_request_target workflow misconfiguration to steal a Personal Access Token. With that PAT, the attackers took control of the repository and pushed a tampered version — 0.69.4 — that ran both the legitimate Trivy scan and a credential harvester.

The harvester scanned for environment variables, SSH keys, cloud provider credentials, database configs, Docker tokens, Kubernetes secrets, even crypto wallets. It encrypted the haul and shipped it to scan.aquasecurtiy[.]org — note the typo in "security," which is honestly the kind of detail that makes attribution reports fun to read. If exfiltration failed, it staged the stolen data in a public GitHub repo named tpcp-docs under the victim's own account. Using the victim's infrastructure as a fallback exfil channel. That's cold.

Then came the tag poisoning

The attackers force-pushed 75 out of 76 version tags in aquasecurity/trivy-action. Every CI/CD pipeline that pinned to a specific version tag — which is what everyone tells you to do for reproducibility — suddenly ran the attacker's payload instead of the real scanner.

This is the supply chain attack that security talks have been warning about for years, executed against a security tool. The irony writes itself.

CanisterWorm: the sequel nobody asked for

Here's where it gets genuinely novel. TeamPCP — the group behind the breach, self-identified in their own source code because apparently even malware authors have branding - didn't stop at credential theft. They used the stolen npm tokens from compromised developer machines to publish malicious updates to 47 npm packages.

The malware, dubbed CanisterWorm, is a self-propagating worm. Early versions needed manual deployment via a deploy.js file. But the iteration found in @teale.io/eslint-config versions 1.8.11 and 1.8.12 evolved: a findNpmTokens() function runs during postinstall, harvests npm tokens, and spawns deploy.js as a fully detached background process. It installs a persistent backdoor via a systemd user service, then uses those tokens to publish itself to more packages.

Self-replicating supply chain malware. That's a sentence I was hoping to not write for at least another year.

The blockchain C2 trick

The C2 mechanism is the cherry on top. CanisterWorm uses an ICP canister - a smart contract on the Internet Computer blockchain - as a dead drop resolver. This is the first publicly documented case of ICP canisters being abused for C2 infrastructure.

Why does this matter? Because blockchain-based C2 is tamperproof and extremely difficult to take down. You can't send a takedown notice to a smart contract. You can't seize its domain. The C2 address lives on decentralized infrastructure by design. For defenders, this is a nightmare scenario that turns every blockchain "feature" into an attacker advantage.

What this actually means for you

If you use aquasecurity/trivy-action in your GitHub Actions workflows, audit your pinned tags immediately. Don't just check the current state - review your CI logs for unexpected network connections to domains that look like typosquatted versions of "aquasecurity."

More broadly, this attack demonstrates something the industry keeps learning the hard way: version pinning is not a security control if the upstream can be compromised. Hash-based pinning (using commit SHAs instead of tags) would have prevented the tag-poisoning stage entirely. The fact that most GitHub Actions workflows still pin to tags rather than SHAs is a collective failure of defaults.

And if you're running npm packages in your build pipeline, check your postinstall scripts. CanisterWorm specifically targets that hook. The worm doesn't need you to run anything manually — npm install is the trigger.

We keep building more automated, more interconnected development pipelines and then acting surprised when attackers find ways to ride those connections. The vulnerability scanner that protects your code became the vector that compromised it. If that doesn't make you rethink your supply chain trust model, I don't know what will.

Gigia Tsiklauri is a Security Architect and founder of Infosec.ge. Get in touch