Skip to content
.ca
5 mincritical

CanisterWorm: npm Publisher Compromise Deploys Backdoor Across 29+ Packages

CanisterWorm is a worm-enabled supply chain attack that compromises legitimate npm publisher accounts to distribute a Python backdoor. The malware establishes user-level Linux persistence via systemd and utilizes an Internet Computer Protocol (ICP) canister as a dead-drop C2 to continuously fetch and execute secondary payloads, while simultaneously harvesting npm tokens to propagate itself to other packages.

Sens:ImmediateConf:highAnalyzed:2026-03-23reports

Authors: Socket Threat Research Team

ActorsCanisterWorm

Source:Socket

IOCs · 5

Key Takeaways

  • Threat actors compromised legitimate npm publisher accounts to deploy a worm-enabled backdoor across 29+ packages in @emilgroup and @teale.io namespaces.
  • The malware uses a Python implant that polls an Internet Computer Protocol (ICP) canister as a dead-drop C2 to fetch and execute secondary payloads.
  • Persistence is achieved on Linux systems via user-level systemd services (systemd --user) named 'pgmon'.
  • A propagation script (deploy.js) harvests npm tokens to autonomously republish the malicious payload to other accessible packages using the '--tag latest' flag.

Affected Systems

  • Linux hosts
  • Developer workstations
  • CI/CD runners
  • Build systems running npm

Attack Chain

The attack begins when a developer or CI system installs a compromised npm package. A postinstall hook executes 'node index.js', which drops a Python backdoor (service.py) and establishes persistence via a user-level systemd service named 'pgmon'. The Python implant continuously polls an ICP canister dead-drop C2 to retrieve URLs for secondary payloads, which are downloaded to '/tmp/pglog' and executed. Concurrently, a worm component (deploy.js) harvests local npm tokens to republish the malicious code to other accessible packages.

Detection Availability

  • YARA Rules: No
  • Sigma Rules: No
  • Snort/Suricata Rules: No
  • KQL Queries: No
  • Splunk SPL Queries: No
  • EQL Queries: No
  • Other Detection Logic: No

The article does not provide specific detection rules such as YARA or Sigma, but outlines behavioral indicators and file paths for hunting.

Detection Engineering Assessment

EDR Visibility: High — EDR solutions should easily detect anomalous systemd service creation, execution of binaries from /tmp, and Node.js spawning systemctl or Python processes. Network Visibility: Medium — Traffic to the ICP canister domain can be monitored, but it is hosted on legitimate Web3 infrastructure (icp0.io), which may blend with normal traffic if ICP is used legitimately in the environment. Detection Difficulty: Moderate — While the persistence mechanisms and file paths are hardcoded and easily detectable, the initial vector relies on legitimate npm package installations, which are noisy in developer environments.

Required Log Sources

  • Process Creation (Event ID 4688 / Sysmon Event ID 1)
  • File Creation (Sysmon Event ID 11)
  • Network Connections (Sysmon Event ID 3)

Hunting Hypotheses

HypothesisTelemetryATT&CK StageFP Risk
Look for Node.js or npm processes spawning systemctl commands with the '--user' flag, indicating potential user-level persistence establishment.Process execution logs (e.g., Sysmon Event ID 1, EDR process telemetry)PersistenceLow to Medium
Search for Python processes making regular outbound network connections to '*.icp0.io' domains, followed by file creation in the /tmp directory.Network connection logs, File creation logsCommand and ControlLow
Identify execution of binaries directly from the /tmp directory, specifically files named 'pglog'.Process execution logsExecutionLow

Control Gaps

  • Lack of strict egress filtering for CI/CD environments
  • Insufficient monitoring of user-level systemd services

Key Behavioral Indicators

  • Creation of a systemd service named 'pgmon'
  • File creation of '/tmp/pglog' and '/tmp/.pg_state'
  • npm publish commands executed autonomously from CI/CD or developer workstations

False Positive Assessment

  • Low. The specific combination of the 'pgmon' service, '/tmp/pglog' execution, and ICP canister C2 is highly distinctive to this malware family.

Recommendations

Immediate Mitigation

  • Identify and remove any installed versions of the compromised @emilgroup and @teale.io packages.
  • Check for and disable the 'pgmon' systemd service on developer workstations and CI runners.
  • Delete malicious artifacts including ~/.local/share/pgmon/service.py, /tmp/pglog, and /tmp/.pg_state.
  • Revoke and rotate any npm publishing tokens that may have been exposed on affected machines.

Infrastructure Hardening

  • Implement strict egress network filtering on CI/CD runners to prevent unauthorized C2 communication.
  • Restrict the ability of npm packages to run postinstall scripts by default using 'npm config set ignore-scripts true'.

User Protection

  • Deploy EDR solutions to developer workstations to monitor for anomalous process execution and persistence mechanisms.
  • Audit developer environments for unauthorized user-level systemd services.

Security Awareness

  • Educate developers on the risks of supply chain attacks and the importance of reviewing package dependencies and postinstall behaviors.

MITRE ATT&CK Mapping

  • T1195.002 - Supply Chain Compromise: Compromise Software Supply Chain
  • T1059.006 - Command and Scripting Interpreter: Python
  • T1543.002 - Create or Modify System Process: Systemd Service
  • T1105 - Ingress Tool Transfer
  • T1552.004 - Unsecured Credentials: Private Keys
  • T1102 - Web Service

Additional IOCs

  • File Paths:
    • /tmp/.pg_state - File used by the implant to track previously downloaded payload URLs to avoid re-downloading.
  • Command Lines:
    • Purpose: Execute the initial loader script during the npm package installation phase. | Tools: node, npm | Stage: Execution | node index.js
    • Purpose: Establish persistence by reloading the user systemd daemon, enabling, and starting the malicious service. | Tools: systemctl, systemd | Stage: Persistence | systemctl --user daemon-reload
    • Purpose: Republish compromised packages to propagate the worm to other accessible namespaces. | Tools: npm | Stage: Lateral Movement | npm publish --access public --tag latest
  • Other:
    • pgmon - Hardcoded systemd service name used for persistence.
    • tdtqy-oyaaa-aaaae-af2dq-cai - ICP canister ID used as the dead-drop C2.
    • deploy.js - Propagation script used to harvest npm tokens and republish packages.