Threat ID: TL-2026-0281 | Severity: CRITICAL | CVE: CVE-2026-33634
Actor: TeamPCP | Motivation: DESTRUCTIVE / CREDENTIAL THEFT
Related Reports: 9 | Available Detections: 81+
Between March 19 and March 24, 2026, a threat actor operating under the moniker TeamPCP executed one of the most sophisticated multi-ecosystem supply chain attacks documented to date. The campaign simultaneously compromised Aqua Security's Trivy vulnerability scanner, BerriAI's LiteLLM AI proxy, Checkmarx's KICS GitHub Action, and propagated a self-replicating worm across 66+ npm packages — affecting CI/CD pipelines, Python environments, and Kubernetes clusters globally.
The scope of this operation is notable not for any single novel technique, but for the coordinated execution across five distinct software ecosystems within a compressed timeframe. TeamPCP exploited residual access from an earlier compromise of the hackerbot-claw VS Code extension (TL-2026-0165), demonstrating how incomplete credential rotation following a security incident can cascade into a much larger event. This article traces the full attack timeline across 9 related threat intelligence reports, provides detection guidance, and maps the campaign to MITRE ATT&CK.
Executive Summary
- What: Coordinated supply chain attack across 5 software ecosystems (GitHub Actions, PyPI, npm, Docker Hub, VS Code Marketplace) — assigned CVE-2026-33634
- Who: TeamPCP — exploiting residual access from an earlier hackerbot-claw VS Code extension compromise (TL-2026-0165) and leveraging stolen publisher credentials for lateral propagation
- Scope: 75 of 76 trivy-action tags poisoned, LiteLLM v1.82.7–1.82.8 backdoored on PyPI, 66+ npm packages compromised via self-replicating worm, 35 KICS GitHub Action release tags hijacked, destructive Kubernetes DaemonSets deployed
- Impact: Credential theft at scale — 50+ credential file paths enumerated per victim, GitHub Actions runner memory scraped via
/proc/*/mem, AES-256-CBC encrypted exfiltration with RSA-4096 key wrapping, and destructive wipers targeting Kubernetes infrastructure - Detection: 81+ production-ready detections available across 9 threat reports on Threadlinqs Intelligence
Technical Analysis
The TeamPCP campaign unfolded in five distinct phases over a 25-day span (Feb 28 – Mar 24), each building on access obtained in the previous phase. The operational pattern suggests a single coordinated actor or small group with pre-positioned access across multiple package registries and CI/CD platforms.
Phase 1: The Genesis — VS Code Extension Compromise (February 28)
The campaign's origin traces to TL-2026-0165, in which the hackerbot-claw VS Code extension was compromised via a stolen Personal Access Token (PAT) belonging to an Aqua Security developer. The attacker published a malicious version to the OpenVSX registry. Aqua Security responded with a credential rotation, but the rotation was incomplete. Residual access to GitHub Actions workflows and associated service accounts remained valid. This gap — between incident response and full credential invalidation — provided TeamPCP the foothold required for everything that followed.
The takeaway is straightforward: credential rotation after a compromise must be exhaustive and verified. A partial rotation is indistinguishable from no rotation if the adversary retains even one valid token.
Phase 2: Trivy Ecosystem Takeover (March 19–20)
TeamPCP used the residual access to compromise the Trivy GitHub Actions ecosystem across three vectors, documented in TL-2026-0256, TL-2026-0263, and TL-2026-0270.
The actor force-pushed 75 of 76 trivy-action tags and all 7 setup-trivy tags to malicious commits. The single uncompromised trivy-action tag appears to have been protected by a branch protection rule that the stolen credentials could not override. The compromised entrypoint.sh script expanded from a legitimate 2,855 bytes to a malicious 17,592 bytes (204 lines), containing:
- Enumeration of 50+ credential file paths including
~/.aws/credentials,~/.docker/config.json,~/.kube/config,~/.npmrc,~/.pypirc, SSH keys, GCP service account JSON, and Azure CLI tokens - Direct reading of GitHub Actions runner memory via
/proc/*/memto extract secrets that had been passed as environment variables or masked inputs — a technique that bypasses GitHub's secret masking in logs - Exfiltration to Cloudflare tunnel endpoints using dynamically generated subdomains under
.trycloudflare.com
Simultaneously, the Trivy v0.69.4 binary release was compromised on Docker Hub. Any CI/CD pipeline pulling aquasecurity/trivy-action@v1 (or any floating tag) between March 19 and the remediation window ingested the malicious payload. Given Trivy's position as one of the most widely adopted open-source vulnerability scanners, the blast radius was substantial.
Phase 3: CanisterWorm npm Propagation (March 20–22)
Documented in TL-2026-0259, a self-propagating npm worm — internally dubbed CanisterWorm — compromised 29 packages in its initial wave, expanding to 66+ packages across the @emilgroup and @teale.io scopes. The propagation mechanism was credential-based: stolen npm publisher tokens from Phase 2's credential harvesting were used to authenticate to the npm registry and publish trojanized versions of packages maintained by the compromised accounts.
The worm's payload included Python implants with systemd persistence masquerading as sysmon.service — a naming choice designed to blend with environments where administrators might expect Sysmon-like tooling. The implants phoned home to Internet Computer Protocol (ICP) blockchain canisters, representing the first documented use of ICP canisters as C2 dead drops in a supply chain attack. The canister at tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io served as an immutable, censorship-resistant coordination point that could not be taken down through traditional domain seizure or hosting provider abuse reports.
Phase 4: LiteLLM PyPI Compromise (March 22)
The core of TL-2026-0281. TeamPCP published trojanized versions of BerriAI's LiteLLM package — v1.82.7 and v1.82.8 — to PyPI. LiteLLM is an AI proxy that abstracts multiple LLM provider APIs behind a unified interface, making it a high-value target given the concentration of API keys in its deployment environments.
The trojanized versions implemented a multi-stage credential stealer:
- .pth file injection: A Python path configuration file was dropped into
site-packages/, ensuring the malicious code executed on every Python interpreter startup — not just when LiteLLM was imported. This is a persistence mechanism that survives virtual environment recreation as long as the compromised package remains installed. - Double base64-encoded payload: The initial .pth file contained a base64-encoded loader that decoded a second base64 layer containing the actual credential stealer. This dual encoding layer was sufficient to evade static analysis by pip audit tooling and most CI/CD security scanners at the time of publication.
- Credential harvesting: The stealer enumerated the same 50+ credential paths seen in Phase 2, with additional targeting of LLM-specific credentials: OpenAI API keys, Anthropic tokens, Azure OpenAI endpoints, Google AI Studio keys, and Hugging Face tokens.
- Hybrid encryption for exfiltration: Harvested credentials were encrypted with AES-256-CBC using a random per-session key, which was then wrapped with RSA-4096 using an embedded public key. This ensured that even if network traffic was captured, decryption required the actor's private key.
- C2 endpoints:
models.litellm.cloud(typosquatted to appear legitimate) andcheckmarx.zone(pre-positioned for the Phase 5 KICS attack)
The choice of LiteLLM as a target reflects an understanding of the current software landscape. AI/ML infrastructure frequently holds credentials for multiple cloud providers, model APIs, and data stores. Compromising a single AI proxy package yields access to a dense cluster of high-value secrets.
Phase 5: KICS GitHub Action and Kubernetes Wiper (March 23–24)
The campaign's final phase, documented in TL-2026-0274 and TL-2026-0279, shifted from credential theft to destructive operations. TeamPCP hijacked 35 Checkmarx KICS release tags on GitHub, injecting payloads that deployed Kubernetes DaemonSets onto any cluster accessible from the compromised CI/CD runner.
Two DaemonSet variants were observed:
host-provisioner-iran— Targeted infrastructure geolocated to Iranian IP ranges. This DaemonSet mounted the host filesystem as read-write, enumerated data volumes, and executed a wipe sequence. The targeting of Iranian infrastructure specifically suggests either geopolitical motivation or an attempt to create a false-flag attribution trail.host-provisioner-std— A general-purpose backdoor DaemonSet that established persistent reverse shell access to compromised nodes. Naming patterns includednode-setup-*andhost-provisioner-*, designed to appear as legitimate infrastructure management workloads.
Both DaemonSets requested privileged pod security contexts, enabling host PID namespace access, host networking, and the ability to read and write arbitrary host paths. In Kubernetes clusters without Pod Security Admission enforcement, these DaemonSets deployed silently across all nodes.
Novel Techniques
Several aspects of this campaign represent documented firsts or rare operational patterns worth highlighting for defenders:
- ICP blockchain canisters as C2 dead drops. The use of Internet Computer Protocol canisters for command-and-control coordination is, to our knowledge, the first documented instance in a supply chain attack. ICP canisters are immutable smart contracts hosted on a decentralized blockchain, making them resistant to traditional takedown mechanisms.
- Self-propagating npm worm via stolen publishing tokens. While typosquatting and dependency confusion are well-documented npm attack vectors, CanisterWorm's use of stolen credentials to propagate through legitimate package maintainer accounts at scale is a qualitative escalation. The worm did not need to trick developers into installing fake packages — it published to packages they already depended on.
- Hybrid encryption for exfiltration (AES-256-CBC + RSA-4096). The use of per-session symmetric keys wrapped with asymmetric encryption ensures that credential payloads remain confidential even if defenders capture network traffic. This represents a higher operational security posture than the plaintext or simple XOR exfiltration seen in most supply chain attacks.
- .pth file injection for Python startup persistence. While .pth files have been discussed in security research, their abuse in a real-world supply chain attack for interpreter-level persistence is uncommon. The technique ensures malicious code runs on every
pythoninvocation, not just on import of the compromised package. - Kubernetes privileged DaemonSet deployment for cross-node compromise. Deploying privileged DaemonSets from compromised CI/CD pipelines represents a direct pipeline-to-production lateral movement path that bypasses traditional network-based detection.
Detection
Threadlinqs Intelligence provides 81+ production-ready detection rules across 9 threat reports covering this campaign. The detection strategy spans three layers: CI/CD pipeline integrity monitoring, endpoint credential access detection, and Kubernetes runtime anomaly detection. Below are three representative rules.
Splunk SPL — Python .pth File Injection in Site-Packages
This rule detects the creation of .pth files in Python site-packages directories, excluding known legitimate entries created by pip and setuptools. The LiteLLM trojan dropped a .pth file to achieve interpreter-level persistence — any new .pth file outside of a known package installation workflow warrants investigation.
SPLindex=* sourcetype=sysmon EventCode=11
| where match(TargetFilename, "site-packages.*\\.pth$")
| where NOT match(TargetFilename, "(setuptools|pip|easy-install)\\.pth")
| stats count by TargetFilename, Image, ComputerName
Sysmon EventCode 11 (FileCreate) is the primary data source. False positives are limited to legitimate Python package installations that create .pth files, which should be baselined in environments with known package management workflows.
Microsoft KQL — /proc/*/mem Reads in CI/CD Environments
The Trivy compromise scraped GitHub Actions runner memory via /proc/*/mem to extract secrets. This KQL query detects file reads targeting process memory files from shell or Python interpreters — behavior that should never occur in a standard CI/CD runner execution.
KQLDeviceFileEvents
| where ActionType == "FileRead"
| where FolderPath matches regex @"/proc/\d+/mem"
| where InitiatingProcessFileName in ("bash", "sh", "python3")
| project Timestamp, DeviceName, InitiatingProcessCommandLine, FolderPath
Any process reading /proc/<pid>/mem from a CI/CD runner context is inherently suspicious. Legitimate debugging tools (gdb, strace) may trigger this in development environments but should not appear in production pipeline runners.
Sigma — TeamPCP Cloudflare Tunnel C2 Communication
TeamPCP used Cloudflare's quick tunnel service (.trycloudflare.com) for C2 communication. This Sigma rule matches DNS queries to the specific tunnel subdomains observed in the campaign. The subdomain naming pattern uses four hyphenated English words generated by Cloudflare's tunnel provisioning system.
SIGMAtitle: TeamPCP Cloudflare Tunnel C2 Communication
id: a7c3e9f1-2b8d-4f6a-9e1c-3d5f7a8b2c4e
status: experimental
description: |
Detects DNS resolution for Cloudflare quick tunnel subdomains associated
with TeamPCP supply chain campaign C2 infrastructure (CVE-2026-33634).
references:
- https://intel.threadlinqs.com/#TL-2026-0281
- https://intel.threadlinqs.com/#TL-2026-0256
author: Threadlinqs Intelligence
date: 2026/03/25
tags:
- attack.command_and_control
- attack.t1102.001
- attack.t1572
- attack.t1071.001
logsource:
category: dns
product: any
detection:
selection:
query|endswith: '.trycloudflare.com'
filter:
query|contains:
- 'championships-peoples-point-cassette'
- 'investigation-launches-hearings-copying'
- 'souls-entire-defined-routes'
- 'plug-tab-protective-relay'
condition: selection and filter
falsepositives:
- Legitimate Cloudflare tunnel usage with coincidentally matching subdomain names (extremely unlikely)
level: critical
Browse all 81+ detection rules across 9 related threat reports: View on Threadlinqs Intelligence
Indicators of Compromise
Network Indicators
| Type | Indicator | Context |
|---|---|---|
| Domain | scan.aquasecurtiy.org | Typosquatted C2 domain (note: "securtiy" misspelling) |
| Domain | models.litellm.cloud | LiteLLM credential exfiltration endpoint |
| Domain | checkmarx.zone | KICS campaign C2 and DaemonSet staging |
| IP | 45.148.10.212 | Primary C2 server (TECHOFF SRV, Amsterdam, NL) |
| ICP Canister | tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io | Blockchain dead drop for CanisterWorm coordination |
| CF Tunnel | championships-peoples-point-cassette.trycloudflare.com | Cloudflare quick tunnel C2 channel 1 |
| CF Tunnel | investigation-launches-hearings-copying.trycloudflare.com | Cloudflare quick tunnel C2 channel 2 |
| CF Tunnel | souls-entire-defined-routes.trycloudflare.com | Cloudflare quick tunnel C2 channel 3 |
| CF Tunnel | plug-tab-protective-relay.trycloudflare.com | Cloudflare quick tunnel C2 channel 4 |
Affected Package Versions
| Package | Version / Scope | Ecosystem | Status |
|---|---|---|---|
litellm | 1.82.7, 1.82.8 | PyPI | Yanked |
trivy | 0.69.4 | Docker Hub / GitHub Releases | Reverted |
trivy-action | 75 of 76 release tags | GitHub Actions | Tags re-signed |
setup-trivy | All 7 release tags | GitHub Actions | Tags re-signed |
kics-github-action | 35 release tags | GitHub Actions | Tags re-signed |
@emilgroup/* | 29+ packages | npm | Unpublished |
@teale.io/* | 37+ packages | npm | Unpublished |
File and Behavioral Indicators
| Type | Indicator | Context |
|---|---|---|
| File | entrypoint.sh (17,592 bytes / 204 lines) | Malicious trivy-action entrypoint |
| File | *.pth in site-packages (non-standard) | LiteLLM Python startup persistence |
| Systemd | sysmon.service | CanisterWorm persistence unit (masquerading) |
| K8s DaemonSet | host-provisioner-iran | Destructive wiper targeting Iranian infrastructure |
| K8s DaemonSet | host-provisioner-std | General-purpose backdoor DaemonSet |
| K8s Pod prefix | node-setup-* | Backdoor pod naming pattern |
| Process | Reads to /proc/*/mem from shell processes | Runner memory scraping for secrets |
Timeline
| Date | Event | Reference |
|---|---|---|
| 2026-02-28 | hackerbot-claw VS Code extension compromised via stolen PAT; malicious version published to OpenVSX | TL-2026-0165 |
| 2026-03-01 | Aqua Security initiates credential rotation (incomplete — residual access persists) | TL-2026-0165 |
| 2026-03-19 | TeamPCP force-pushes 75/76 trivy-action tags and 7/7 setup-trivy tags to malicious commits | TL-2026-0256 |
| 2026-03-19 | Compromised entrypoint.sh begins harvesting credentials and reading runner memory via /proc/*/mem | TL-2026-0263 |
| 2026-03-20 | Trivy v0.69.4 binary release compromised on Docker Hub | TL-2026-0270 |
| 2026-03-20 | CanisterWorm initial wave compromises 29 npm packages across @emilgroup scope | TL-2026-0259 |
| 2026-03-21 | CanisterWorm spreads to @teale.io scope; total reaches 50+ packages | TL-2026-0259 |
| 2026-03-22 | Trojanized LiteLLM v1.82.7 published to PyPI with .pth persistence and hybrid-encrypted exfiltration | TL-2026-0281 |
| 2026-03-22 | LiteLLM v1.82.8 published with identical payload; npm worm count exceeds 66 packages | TL-2026-0281 |
| 2026-03-23 | 35 Checkmarx KICS GitHub Action release tags hijacked | TL-2026-0274 |
| 2026-03-23 | Destructive Kubernetes DaemonSets (host-provisioner-iran, host-provisioner-std) begin deploying from compromised pipelines | TL-2026-0279 |
| 2026-03-24 | Aqua Security, BerriAI, and Checkmarx issue coordinated security advisories; compromised packages yanked/reverted | CVE-2026-33634 |
| 2026-03-25 | CVE-2026-33634 assigned; CVSS score pending; community-wide credential rotation campaigns underway | This report |
MITRE ATT&CK Mapping
| Tactic | Technique | ID | Campaign Usage |
|---|---|---|---|
| Initial Access | Supply Chain Compromise: Software Supply Chain | T1195.002 | Poisoned trivy-action tags, LiteLLM PyPI packages, KICS Action, and 66+ npm packages |
| Execution | Command and Scripting Interpreter | T1059 | Malicious entrypoint.sh (bash), Python .pth loaders, npm postinstall scripts |
| Credential Access | Unsecured Credentials | T1552 | Enumeration of 50+ credential file paths (AWS, GCP, Azure, Docker, Kube, SSH, npm, PyPI) |
| Exfiltration | Exfiltration Over Web Service | T1567.001 | Credential exfiltration to Cloudflare tunnel endpoints and typosquatted domains |
| Command and Control | Web Service: Dead Drop Resolver | T1102.001 | ICP blockchain canisters as immutable C2 coordination points |
| Command and Control | Asymmetric Cryptography | T1573.002 | AES-256-CBC + RSA-4096 hybrid encryption for exfiltrated credential payloads |
| Persistence | Create or Modify System Process: Systemd Service | T1543.002 | sysmon.service systemd unit for CanisterWorm persistence on Linux hosts |
| Execution | Deploy Container | T1610 | Privileged Kubernetes DaemonSets deployed from compromised CI/CD pipelines |
| Privilege Escalation | Escape to Host | T1611 | Privileged pod security context enabling host filesystem and PID namespace access |
| Impact | Data Destruction | T1485 | host-provisioner-iran DaemonSet executing destructive wipe operations |
| Defense Evasion | Deobfuscate/Decode Files or Information | T1140 | Double base64-encoded payload in .pth files to evade static analysis |
Full MITRE ATT&CK mapping across all 9 related threats: View coverage on Threadlinqs
Recommendations
- Pin GitHub Actions to full commit SHAs, never floating tags. This campaign would have had no impact on pipelines that pinned
aquasecurity/trivy-actionandcheckmarx/kics-github-actionto specific commit hashes rather than version tags. Tags are mutable references — SHAs are not. Audit all workflow files for tag-based references and replace them with pinned commits. Tools such aspinactcan automate this across repositories. - Audit Python .pth files in all site-packages directories. Run
find / -name "*.pth" -path "*/site-packages/*" 2>/dev/nulland verify every entry against known legitimate packages (setuptools, pip, easy-install). Any .pth file that was not created by a recognized package manager installation is a persistence indicator requiring immediate investigation. - Verify Trivy binary checksums against Aqua Security's security advisory. If your environment pulled Trivy v0.69.4 between March 19 and March 24, treat the binary as compromised. Re-download from a verified source and compare SHA-256 hashes against the values published in Aqua's advisory. Rebuild any container images that embedded the compromised binary.
- Block IOC domains at DNS and proxy level. Add
scan.aquasecurtiy.org,models.litellm.cloud,checkmarx.zone, and the four.trycloudflare.comsubdomains to DNS sinkholes and web proxy block lists. Monitor for historical resolution of these domains in DNS logs to identify previously compromised systems. - Monitor Kubernetes clusters for unauthorized privileged DaemonSets. Alert on any DaemonSet creation requesting privileged security context, host PID namespace, or host filesystem mounts that does not match an approved allowlist. Pod names matching
node-setup-*orhost-provisioner-*patterns warrant immediate investigation. Enforce Pod Security Admission at the Restricted level where operationally feasible.
References
- Threadlinqs Intelligence — TL-2026-0281: TeamPCP LiteLLM Supply Chain Compromise
- Threadlinqs Intelligence — TL-2026-0256: Trivy GitHub Actions Tag Poisoning
- Threadlinqs Intelligence — TL-2026-0259: CanisterWorm npm Propagation
- Threadlinqs Intelligence — TL-2026-0263: Trivy Runner Memory Scraping
- Threadlinqs Intelligence — TL-2026-0270: Trivy Binary Release Compromise
- Threadlinqs Intelligence — TL-2026-0274: Checkmarx KICS Action Hijack
- Threadlinqs Intelligence — TL-2026-0279: Kubernetes Wiper DaemonSets
- Threadlinqs Intelligence — TL-2026-0165: hackerbot-claw VS Code Extension Compromise
- Aqua Security — Trivy Action Security Advisory
- BerriAI — LiteLLM Security Advisory
- Checkmarx — KICS GitHub Action Security Advisory
- NVD — CVE-2026-33634
Full threat intelligence, detection rules, and IOC feeds are available on Threadlinqs Intelligence. Track this threat: TL-2026-0281.