On March 20, 2026, at around 20:45 UTC, a large-scale compromise of npm packages was detected. What made this incident stand out wasn’t just the number of affected packages, but the method used. The attackers introduced a previously unseen worm-like mechanism that leveraged decentralized infrastructure for command-and-control.
This campaign has been named CanisterWorm due to its use of an Internet Computer (ICP) canister as a dead-drop mechanism. This is not something typically seen in supply chain attacks, making it both innovative and difficult to disrupt.
Within a very short period, multiple npm packages were infected, including entire scopes such as @EmilGroup and @opengov, along with standalone packages. Evidence suggests that this attack is closely related to the earlier compromise involving Trivy, likely conducted by the same threat actor group known as TeamPCP.

The CanisterWorm campaign represents a multi-stage supply chain attack targeting npm packages. The attacker used compromised credentials to inject malicious code into legitimate packages and distribute it through normal installation workflows.
The malware chain consists of:
- A Node.js postinstall script (initial infection)
- A persistent Python-based backdoor
- A decentralized C2 system hosted on ICP
The attack evolved rapidly, moving from manual propagation to fully automated self-spreading behavior within hours.
Affected Assets
- 28 packages under @EmilGroup
- 16 packages under @opengov
- @teale.io/eslint-config
- @airtm/uuid-base32
- @pypestream/floating-ui-dom
Attack Timeline
- 20:45 UTC – Initial compromise detected
- Within 60 seconds – 28 packages modified and republished
- ~1 hour later – Worm upgraded to self-propagating version
Multi-Stage Infection Flow
The attack uses a layered approach:
- A malicious Node.js script executes during npm install
- It drops a Python backdoor on the system
- The backdoor connects to a decentralized ICP canister
- The canister provides a URL to download further payloads
This design allows attackers to update payloads remotely without modifying the original infected packages.
Persistence Mechanism
The malware installs itself as a systemd user service, meaning:
- No root access is required
- It survives system reboots
- It automatically restarts if stopped
This makes removal difficult, especially for developers who may not inspect user-level services regularly.
Stealth Techniques
The attackers took care to remain unnoticed:
- Files are named like PostgreSQL components (pgmon, pglog)
- Errors are silently ignored
- Installation appears completely normal
- Payload activates only on Linux systems
Command and Control via ICP
Instead of using traditional servers, the malware communicates with an ICP canister, which:
- Acts as a decentralized dead-drop
- Returns URLs for payload downloads
- Cannot be easily taken down
This is a significant shift from typical centralized C2 infrastructure.
Sandbox Evasion
The malware delays execution:
- Waits 5 minutes before first activity
- Checks for updates every ~50 minutes
This helps it bypass many automated analysis environments.
Payload Behavior
Stage 1: Node.js Loader
The initial script:
- Decodes a base64-encoded Python payload
- Writes it to the user’s home directory
- Configures systemd persistence
- Starts the malicious service
Stage 2: Python Backdoor
Once active, the backdoor:
- Contacts the ICP endpoint
- Retrieves a URL for the next payload
- Downloads and executes it
- Stores state to avoid duplicate downloads
It also includes a clever “kill switch”:
If the returned URL contains YouTube, the malware stays inactive.
Stage 3: Payload Delivery
The final payload is flexible:
- Can be replaced anytime by the attacker
- Runs independently of the backdoor
- Multiple payloads can run simultaneously
Worm Capabilities
Initial Version (Manual Spread)
At first, the attacker used a script (deploy.js) to:
- Use stolen npm tokens
- Identify owned packages
- Increment version numbers
- Publish malicious updates
This allowed rapid spread across multiple packages.
Advanced Version (Self-Propagation)
Later, the worm became autonomous.
It now:
- Scans .npmrc files for tokens
- Extracts tokens from environment variables
- Queries npm config directly
- Uses stolen credentials to infect more packages
This turns every infected developer machine into a propagation node.
Indicators of Compromise (IOCs)
Network
- ICP endpoint used as C2
- Dynamic payload URLs returned
Filesystem
- ~/.local/share/pgmon/service.py
- ~/.config/systemd/user/pgmon.service
- /tmp/pglog
- /tmp/.pg_state
Behavioral Indicators
- Unexpected systemd user services
- Silent background processes
- Unauthorized npm package updates
C2 Infrastructure
hxxps://tdtqy-oyaaa-aaaae-af2dq-cai[.]raw[.]icp0[.]io/— ICP canister dead-drop resolver
Filesystem Indicators
~/.local/share/pgmon/service.py— Python backdoor script~/.config/systemd/user/pgmon.service— Systemd persistence unit/tmp/pglog— Downloaded binary payload/tmp/.pg_state— State tracking file
Malicious index.js Hashes (SHA256)
e9b1e069efc778c1e77fb3f5fcc3bd3580bbc810604cbf4347897ddb4b8c163b— Wave 1: dry run (empty payload, manual deploy)61ff00a81b19624adaad425b9129ba2f312f4ab76fb5ddc2c628a5037d31a4ba— Wave 2: armed ICP backdoor, manual deploy0c0d206d5e68c0cf64d57ffa8bc5b1dad54f2dda52f24e96e02e237498cb9c3a— Wave 3: self-propagating, test payloadc37c0ae9641d2e5329fcdee847a756bf1140fdb7f0b7c78a40fdc39055e7d926— Wave 4: final form (self-propagating + armed ICP backdoor)
Malicious deploy.js Hashes (SHA256)
f398f06eefcd3558c38820a397e3193856e4e6e7c67f81ecc8e533275284b152— Wave 1- 7df6cef7ab9aae2ea08f2f872f6456b5d51d896ddda907a238cd6668ccdc4bb7 — Wave 2
5e2ba7c4c53fa6e0cef58011acdd50682cf83fb7b989712d2fcf1b5173bad956— Wave 3
Threat Assessment
This attack is particularly dangerous because:
- It spreads through trusted software channels
- It uses legitimate developer workflows
- It leverages decentralized infrastructure
- It evolves rapidly
If fully activated, it could result in large-scale supply chain compromise across thousands of projects.
Our Analysis and Opinion
From a defensive standpoint, this incident highlights a shift in how modern supply chain attacks are being designed. The use of decentralized infrastructure, particularly ICP canisters, is not just a technical novelty—it’s a strategic move. Traditional mitigation approaches often rely on blocking domains, taking down servers, or coordinating with hosting providers. In this case, those methods become far less effective because there is no single point of failure.
What stands out even more is how quickly the attackers iterated. Within a short timeframe, the campaign moved from a manually operated infection model to a fully automated worm. That suggests a high level of preparation and testing behind the scenes. It doesn’t feel experimental; it feels deliberate and staged.
Another concerning aspect is the targeting of developer environments. By focusing on npm tokens and CI/CD pipelines, the attackers are essentially weaponizing trust relationships. Developers typically have broad publishing permissions, and once those credentials are exposed, the blast radius expands significantly. This creates a cascading effect where one compromised machine can lead to dozens or even hundreds of poisoned packages.
The stealth techniques are also worth noting. Naming artifacts after PostgreSQL components is simple, but effective. Most developers would not question a service named “pgmon” running in the background. Combined with silent error handling and delayed execution, the malware avoids raising immediate suspicion.
In our view, this attack is less about immediate payload execution and more about building infrastructure for future operations. The presence of a “kill switch” and placeholder payloads suggests that the attackers were testing deployment pipelines before activating the full malicious capability. That’s a strong indicator of long-term intent.
Defending against this kind of threat requires a shift in mindset. It’s no longer enough to trust packages based on popularity or reputation. Continuous monitoring, token security, and stricter CI/CD controls are becoming essential. Organizations should also consider isolating build environments and limiting token permissions wherever possible.
Overall, CanisterWorm represents a new generation of supply chain attacks—modular, decentralized, and highly adaptive. It’s a reminder that the software ecosystem is only as secure as its weakest dependency.
Conclusion
The CanisterWorm campaign is a clear example of how supply chain attacks are evolving. By combining automation, stealth, and decentralized control, attackers have created a system that is both scalable and resilient.
For developers and organizations, this serves as a critical warning: dependency trust must be continuously validated, and security controls must evolve alongside emerging threats.
