CanisterWorm npm Supply Chain Compromise — Worm-Enabled Backdoor Across 29+ Packages via Publisher Credential Theft

CanisterWorm npm Supply Chain Compromise (TL-2026-0259), also tracked as CanisterWorm, is a high-severity supply-chain compromise scored CVSS 8.6, first published 2026-03-20. It is attributed to TeamPCP with high confidence, affects emilgroup @emilgroup/account-sdk, maps to 15 MITRE ATT&CK techniques (T1005, T1027, T1036), and is covered by 9 detection rules and 20 indicators of compromise.

Key facts for TL-2026-0259

Threat ID
TL-2026-0259
Also known as
CanisterWorm
Severity
HIGH
CVSS
8.6 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)
Status
MONITORING
Category
SUPPLY_CHAIN
First published
2026-03-20
Last reviewed
2026-03-20
Attribution
TeamPCP
Attribution confidence
HIGH
Motivation
financial
Target sectors
financial, insurance, technology, software-development
Target regions
Global, Europe
Detection rules
9
Indicators of compromise
20

Malware and tooling in CanisterWorm npm Supply Chain Compromise

Malware and tooling: tdtqy-oyaaa-aaaae-af2dq-cai

A threat actor compromised npm publishing credentials to deploy backdoored versions across 29+ packages in the @emilgroup and @teale.io scopes. The attack employs a worm-like deploy.js component that propagates via stolen npm tokens, installs a Python implant with systemd persistence, and communicates through an Internet Computer blockchain C2 canister shared with the trivy-action compromise (TL-2026-0256).

How CanisterWorm npm Supply Chain Compromise works

CanisterWorm is a multi-stage supply chain attack targeting the npm ecosystem, discovered by Socket Security's research team on March 20, 2026. The campaign compromised 58 package versions across 29+ packages primarily within the @emilgroup scope (an insurance/financial SDK provider) and the @teale.io scope.

The attack chain begins with the theft of npm publishing tokens or equivalent CI/CD publishing credentials. The threat actor leveraged a custom worm component (deploy.js) that accepts stolen npm tokens from environment variables, resolves associated usernames via npm's /-/whoami endpoint, enumerates all packages each token can publish, bumps patch versions, and republishes malicious content with --tag latest to maximize installation impact. The worm preserves original READMEs to camouflage the malicious updates.

Compromised packages replace legitimate SDK functionality with a minimal framework containing a postinstall hook that invokes node index.js. The initial staging phase used a base64-encoded payload loaded from process.env.PAYLOAD or package config, exiting silently if no payload was present — a dry-run behavior suggesting careful operational staging. The weaponized phase hardcoded the payload directly, deploying a Python script to ~/.local/share/pgmon/service.py.

The Python implant (service.py) implements a deliberate delayed-execution strategy: it sleeps 300 seconds on startup before entering an endless polling loop at 3,000-second intervals. It queries the Internet Computer Protocol (ICP) blockchain canister at tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io, which functions as a dead-drop C2 channel. When the canister returns a URL, the implant downloads a binary to /tmp/pglog, marks it executable, and launches it as a detached process. Downloaded URLs are logged to /tmp/.pg_state to prevent re-downloads. Notably, URLs containing youtube.com are ignored — indicating a dormant or disarmed state mechanism.

Persistence is achieved through systemd user-level services. The Node.js loader creates ~/.config/systemd/user/pgmon.service with Restart=always, reloads the user daemon, enables the service, and starts it immediately — all without requiring root privileges. The service name pgmon masquerades as a PostgreSQL monitoring process.

A critical mutation was identified in @teale.io/eslint-config (versions 1.8.9 and 1.8.10), which extended the attack by harvesting npm tokens from .npmrc files, environment variables, and npm configuration — making propagation more autonomous and increasing the worm's reach beyond the initially compromised token set.

The C2 infrastructure uses an Internet Computer Protocol canister (tdtqy-oyaaa-aaaae-af2dq-cai), providing blockchain-based resilience against traditional domain takedowns. This same canister is shared with the trivy-action supply chain compromise (TL-2026-0256), where a malicious Trivy scanner binary (version 0.69.4) communicated with the identical ICP endpoint. The trivy-action attack compromised 76 of 77 GitHub Actions release tags, scraped CI/CD runner memory for secrets, and exfiltrated data to a typosquatted domain (scan.aquasecurtiy.org). The shared C2 infrastructure strongly suggests a common threat actor or coordinated campaign across both the npm and GitHub Actions ecosystems.

The @emilgroup packages are SDKs for insurance and financial services, indicating potential targeting of organizations in these sectors. The combination of supply chain compromise, credential harvesting for self-propagation, blockchain-based C2, and cross-ecosystem infrastructure sharing represents a sophisticated and evolving threat to software supply chain security.

MITRE ATT&CK techniques used in TL-2026-0259

collection

T1005 Data from Local System

defense-evasion

T1027 Obfuscated Files or Information; T1036 Masquerading; T1070 Indicator Removal

execution

T1059 Command and Scripting Interpreter; T1204 User Execution

command-and-control

T1071 Application Layer Protocol; T1102 Web Service; T1105 Ingress Tool Transfer

initial-access

T1195 Supply Chain Compromise

credential-access

T1528 Steal Application Access Token; T1552 Unsecured Credentials

persistence

T1543 Create or Modify System Process

resource-development

T1584 Compromise Infrastructure; T1586 Compromise Accounts

Affected products and versions in CanisterWorm npm Supply Chain Compromise

  • emilgroup — @emilgroup/account-sdk
    Vulnerable versions: 1.41.1; 1.41.2
  • emilgroup — @emilgroup/account-sdk-node
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/accounting-sdk-node
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/auth-sdk
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/auth-sdk-node
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/billing-sdk
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/billing-sdk-node
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/claim-sdk
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/claim-sdk-node
    Vulnerable versions: patch .x.1, .x.2 versions
  • emilgroup — @emilgroup/customer-sdk
    Vulnerable versions: patch .x.1, .x.2 versions

Remediation for CanisterWorm npm Supply Chain Compromise

Patches

  • Remove compromised @emilgroup package versions (.x.1 and .x.2 patch bumps)
  • Remove @teale.io/eslint-config versions 1.8.9 and 1.8.10
  • Verify integrity of replacement versions against known-good checksums before upgrading

Immediate actions

  • Audit all projects for @emilgroup/* and @teale.io/eslint-config dependencies immediately
  • Check for presence of ~/.local/share/pgmon/service.py on developer machines and CI/CD runners
  • Check for pgmon systemd user service: systemctl --user status pgmon
  • Remove /tmp/pglog and /tmp/.pg_state if present
  • Revoke and rotate ALL npm publishing tokens that may have been exposed
  • Block outbound traffic to tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io at network perimeter
  • Scan CI/CD environments for unauthorized postinstall hooks in node_modules

Workarounds

  • Pin exact package versions in package-lock.json and verify checksums
  • Use npm install --ignore-scripts to prevent postinstall execution during audit
  • Temporarily replace @emilgroup SDK packages with local forks if business-critical

Longer-term hardening

  • Implement package-lock.json enforcement with npm ci instead of npm install
  • Enable npm audit in CI/CD pipelines with fail-on-vulnerability policies
  • Deploy Software Composition Analysis (SCA) tooling like Socket.dev or Snyk
  • Implement allowlisted postinstall scripts via .npmrc ignore-scripts=true with explicit overrides
  • Monitor npm token usage via npm access audit logs
  • Implement EDR with behavioral detection for unexpected systemd service creation

Weaknesses (CWE) in CanisterWorm npm Supply Chain Compromise

CWE-506, CWE-829, CWE-494, CWE-912

Timeline of CanisterWorm npm Supply Chain Compromise

  • Estimated initial compromise of npm publishing tokens for @emilgroup scope based on package version analysis
  • Threat actor deploys dry-run versions across @emilgroup packages with base64 payload loader that exits silently — operational staging and testing phase
  • Weaponized versions deployed: hardcoded Python implant with pgmon systemd persistence and ICP blockchain C2 communication replaces dry-run loader
  • @teale.io/eslint-config versions 1.8.9 and 1.8.10 published with npm token harvesting mutation — extends worm propagation capability beyond initial token set
  • Related trivy-action supply chain compromise detected on GitHub Actions runners, sharing identical ICP C2 canister infrastructure
  • Aikido Security researcher Charlie Eriksen independently discloses @teale.io/eslint-config token harvesting variant
  • CrowdStrike publishes analysis of trivy-action compromise confirming shared C2 infrastructure via ICP canister tdtqy-oyaaa-aaaae-af2dq-cai
  • Socket Security Research Team publishes full technical analysis of CanisterWorm campaign identifying 29+ compromised packages and worm propagation mechanism
  • As of 2026-05-29, this specific CanisterWorm incident is contained: the original @emilgroup/@teale.io packages are flagged/pulled and the ICP canister C2 was disarmed by the actor (returns only a Rick Roll link) after March 20 disclosure. However, the actor is now attributed to TeamPCP, which remains active with successor worms (CanisterSprawl, Mini Shai-Hulud) using the same takedown-resistant blockchain-C2 tradecraft, so continued monitoring is warranted.

Sources cited for CanisterWorm npm Supply Chain Compromise

Threats related to CanisterWorm npm Supply Chain Compromise

Detection coverage for TL-2026-0259

As of 2026-03-20, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-0259 across Splunk SPL, Microsoft KQL and Sigma, covering 20 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.

Further reading

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Latest Threats