0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CanisterWorm: A self propagating npm worm opening backdoors in every codebase it touches

0
Posted at

Introduction

This vulnerability is a direct consequence of the Trivy supply chain attack. After compromising Trivy's infrastructure, TeamPCP used it as a launchpad to deploy a self-propagating worm that spread through the npm ecosystem. The worm steals publish tokens, injects itself into packages, persists through reboots via systemd, and uses the ICP (Internet Computer Protocol) blockchain as an uncensorable command-and-control channel.

Attack Chain

The attack unfolds in five stages, each building on the previous one to expand the worm's reach.

Stage 1 — Token Harvesting via Trivy

TeamPCP's compromised Trivy infrastructure — trivy-action, setup-trivy, and the infected binary — was already running inside CI/CD pipelines worldwide. The malware exfiltrated environment variables from these pipelines, specifically targeting NPM_TOKEN values. The infected binary communicated with a typosquatted endpoint (scan.aquasecurtiy.org, note the misspelling) to receive stolen credentials.

Every repository that ran the compromised Trivy tooling during the attack window had its npm publish tokens stolen.

Stage 2 — Persistence via systemd

Once executed, the worm writes a Python backdoor (service.py) to disk and installs a systemd user service (pgmon.service) configured with Restart=always. This means the backdoor:

  • Survives process termination
  • Survives reboots
  • Persists indefinitely until manually discovered and removed

Stage 3 — Blockchain-Based Command and Control

The systemd service begins polling an ICP (Internet Computer Protocol) canister — a smart contract running on the Internet Computer blockchain. ICP was chosen deliberately: it is decentralized with no central authority, making it effectively impossible to take down or file complaints against. There is no registrar to contact, no hosting provider to issue an abuse report to.

The canister serves malicious binaries that the worm downloads and executes as second-stage payloads.

Stage 4 — Self-Propagation Through npm

A deploy.js script is also written to disk. This script:

  1. Gathers all npm publish tokens available in the environment
  2. Identifies which packages those tokens have publish access to
  3. Injects the malicious payload into each package
  4. Publishes the infected version with the latest tag

Anyone who installs an infected package (via npm install package-name, which defaults to latest) gets compromised. Their environment then becomes another propagation point — the worm harvests their tokens and infects any packages they can publish to. This creates an exponential spread pattern across the npm ecosystem.

Stage 5 — Destructive Payloads

The second-stage binary downloaded from the ICP canister fingerprints the host environment and selects its behavior accordingly:

  • Kubernetes clusters detected: Attempts to delete clusters and workloads
  • General Linux systems: Executes rm -rf --no-preserve-root /, destroying the entire filesystem
  • Other environments: Remains as a passive backdoor, awaiting further instructions from the C2 canister

How to Check If You're Compromised

Indicators of Compromise (IoCs)

Check for the presence of the following artifacts on any machine that ran the compromised Trivy tooling or installed a potentially infected npm package:

Artifact Path Significance
Python implant ~/.local/share/pgmon/service.py Confirms malware executed
systemd persistence ~/.config/systemd/user/pgmon.service Confirms persistence was established
Second-stage binary /tmp/pglog Confirms C2 delivery occurred
State tracker /tmp/.pg_state Confirms download state tracking

Other Signs

  • Unexpected references to scan.aquasecurtiy.org (typosquatted domain) in logs or network traffic
  • Unknown ICP canister endpoints in your code or environment
  • Unexplained postinstall scripts in packages you maintain
  • npm package versions published that you did not author

Remediation: What to Do If You're Affected

  1. Confirm execution: Check for the presence of ~/.local/share/pgmon/service.py and ~/.config/systemd/user/pgmon.service. Their existence is proof that the malicious code ran on your system.

  2. Stop the persistence service:

    systemctl --user stop pgmon.service
    systemctl --user disable pgmon.service
    rm ~/.config/systemd/user/pgmon.service
    rm -rf ~/.local/share/pgmon/
    rm -f /tmp/pglog /tmp/.pg_state
    systemctl --user daemon-reload
    
  3. Rotate npm tokens immediately: Revoke and regenerate every npm token that was present in the environment or on the machine where the malware executed.

  4. Rotate all other secrets: CI/CD secrets, cloud credentials, SSH keys, API tokens, and any other sensitive values present in the compromised environment should be assumed stolen and rotated.

  5. Audit your published packages: Check if any packages you maintain had unauthorized version bumps or unexpected postinstall scripts added. If so, unpublish the malicious versions and publish clean replacements.

  6. Pin package versions: Update your package.json and lock files to pin dependencies to known safe versions rather than relying on latest.

References

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?