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
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
credential-access
T1528 Steal Application Access Token; T1552 Unsecured Credentials
persistence
T1543 Create or Modify System Process
resource-development
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
- Socket Security: CanisterWorm — npm Publisher Compromise Deploys Backdoor Across 29+ Packages
- CrowdStrike: From Scanner to Stealer — Inside the Trivy Action Supply Chain Compromise (Shared C2 Infrastructure)
- Aikido Security: Discovery of @teale.io/eslint-config npm Token Harvesting Mutation
- npm Security Advisory: @emilgroup Scope Compromise
- Internet Computer Protocol — Canister Smart Contracts Documentation
- MITRE ATT&CK: Supply Chain Compromise — Compromise Software Supply Chain (T1195.002)
Threats related to CanisterWorm npm Supply Chain Compromise
- Trivy Supply Chain Compromise — TeamPCP Credential-Stealing Malware Injected into CI/CD Pipelines (CVE-2026-33634)
- Trivy Supply Chain Attack — Credential Theft Infostealer via Malicious GitHub Actions Tags (GHSA-69fq-xp46-6x23)
- TeamPCP Supply Chain Campaign: LiteLLM PyPI Compromise, CanisterWorm npm Propagation, and Multi-Ecosystem Attack (CVE-2026-33634)
- Checkmarx KICS GitHub Action Supply Chain Compromise by TeamPCP (kics-github-action Tag Hijacking)
- Trivy Supply Chain Compromise by TeamPCP — Credential-Stealing Malware in v0.69.4, trivy-action, and setup-trivy GitHub Actions
- TeamPCP Supply Chain Attack on LiteLLM — Trojanized PyPI Packages with .pth Persistence and Multi-Stage Credential Stealer
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.