durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3) — Microsoft-Published Azure Durable Functions SDK Trojanized w/ Cross-Cloud Credential Stealer + Linux Disk Wiper (TeamPCP / Mini Shai-Hulud)

durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3) (TL-2026-0580), also tracked as durabletask trojanization, is a critical-severity supply-chain compromise, first published 2026-05-25. It is attributed to TeamPCP with high confidence, affects Microsoft durabletask (Azure Durable Functions Python SDK), references 1 CVE (CVE-2026-45321), maps to 31 MITRE ATT&CK techniques (T1005, T1021.007, T1027), and is covered by 9 detection rules and 25 indicators of compromise.

Key facts for TL-2026-0580

Threat ID
TL-2026-0580
Also known as
durabletask trojanization, Mini Shai-Hulud durabletask wave, TeamPCP W21 PyPI wave, Microsoft Azure Durable Functions SDK compromise
Severity
CRITICAL
Status
MONITORING
Category
SUPPLY_CHAIN
First published
2026-05-25
Last reviewed
2026-05-25
Attribution
TeamPCP
Attribution confidence
HIGH
Motivation
FINANCIAL
Target sectors
technology, cloud, financial, healthcare, government, manufacturing, telecommunications, media, education, saas
Target regions
Global, North America, Europe, Asia-Pacific
Detection rules
9
Indicators of compromise
25

Malware and tooling in durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

Malware and tooling: Mini Shai-Hulud, Shai-Hulud framework, Session messenger (getsession.org)

TeamPCP trojanized the officially Microsoft-published `durabletask` Python SDK (Azure Durable Functions client, ~417K monthly downloads) on PyPI on 2026-05-19, publishing three malicious versions (1.4.1, 1.4.2, 1.4.3) inside a ~35-minute window before yank. The dropper is injected directly into the package's Python source files, so a bare `import durabletask` triggers execution. The second-stage payload is a cross-cloud credential stealer and worm targeting AWS, Azure, GCP, HashiCorp Vault, 1Password, and Bitwarden, propagating via AWS SSM (EC2) and `kubectl exec` (Kubernetes), and carrying a Linux disk wiper.

How durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3) works

On 2026-05-19, threat actor TeamPCP (the operator behind the Mini Shai-Hulud npm wave and the GitHub-internal breach via Nx Console v18.95.0) published three trojanized versions (1.4.1, 1.4.2, 1.4.3) of the official Microsoft-published `durabletask` Python SDK to PyPI. The package is Microsoft's Azure Durable Functions Python client with approximately 417,000 monthly downloads at the time of compromise. PyPI maintainers and Microsoft yanked the versions within approximately 35 minutes of the first publish, but during that window any `pip install durabletask` (including transitive resolutions in CI/CD pipelines, ephemeral runners, and developer workstations) would have pulled the malicious build. This is the first officially-Microsoft-published package surface trojanized in the TeamPCP campaign.

## Initial Access & Trigger

Unlike typical supply-chain droppers that piggyback on `setup.py` / `pyproject.toml` install hooks, TeamPCP injected the dropper directly into the package's Python source files. This means execution occurs not at install time, but at **import time** — a single `import durabletask` (or any transitive import via Azure Functions Python tooling) is sufficient to execute the dropper. This bypasses install-time scanners that focus on package metadata and `setup.py` post-install hooks, and it ensures execution on any host that ever loaded the SDK during the compromise window, including hosts where the affected version was later upgraded out.

## Exploit Chain

1. **Initial Access (T1195.002 — Compromise Software Supply Chain).** Maintainer credentials for the official Microsoft `durabletask` PyPI project were used to publish v1.4.1, then v1.4.2, then v1.4.3 within ~35 minutes on 2026-05-19. The exact credential-theft vector against Microsoft's PyPI publishing identity has not been disclosed in public reporting, but the broader TeamPCP campaign has consistently abused OIDC tokens and harvested CI/CD secrets (cf. CVE-2026-45321, the TanStack OIDC abuse chain that fed the Nx Console publish). 2. **Execution (T1059.006 — Python).** The Python source files of the package are mutated to include a small bootstrapping stub that runs on module import. Because Python evaluates top-level statements when a module is first loaded, no install-time hook is required. 3. **Defense Evasion (T1027 — Obfuscated Files or Information).** The dropper stub is obfuscated and minified to avoid casual review of the package's source on PyPI, and the second-stage payload is fetched dynamically — the package on PyPI does not itself carry the credential-stealer bytes. 4. **Credential Access (T1552 — Unsecured Credentials, T1555 — Credentials from Password Stores, T1528 — Steal Application Access Token).** The second stage enumerates AWS, Azure, GCP, HashiCorp Vault, 1Password, and Bitwarden credential stores and harvests environment-resident tokens, including GitHub PATs and npm granular access tokens. 5. **Discovery (T1057, T1082, T1018).** Cloud-provider metadata services are queried (IMDS/IMDSv2 on AWS, Azure IMDS, GCE metadata) to discover instance identity, role bindings, and reachable peers. 6. **Lateral Movement (T1021.007 — Cloud Services, T1609 — Container Administration Command).** When running inside an EC2 instance with an attached IAM role that permits SSM, the worm uses AWS Systems Manager (`ssm:SendCommand`, `ssm:StartSession`) to execute commands on peer EC2 instances. When running inside a Kubernetes pod with a service-account that permits `pods/exec`, the worm uses `kubectl exec` to execute commands inside other pods. Both pivots deliver and re-execute the same payload, producing a worm that propagates inside cloud accounts and clusters rather than across the public internet. 7. **Exfiltration (T1567 — Exfiltration Over Web Service, T1573 — Encrypted Channel).** Harvested credentials and secrets are encrypted (PBKDF2-derived key, AES) and exfiltrated to Session messenger infrastructure: `filev2.getsession.org` (file delivery) and `seed1.getsession.org` (seed/control). The Session-messenger dead-drop pattern is shared with the @antv npm wave and the broader Mini Shai-Hulud lineage. 8. **Impact (T1485 — Data Destruction, T1561 — Disk Wipe).** iTnews reporting characterizes the durabletask second stage as carrying a Linux disk wiper. Unlike the W20 @ctrl/tinycolor wave, which gated wipe behavior on a 1-in-6 locale-conditional roll, the durabletask wiper materially extends destructive capability and removes the locale gating documented in prior waves. Any host that imported the trojanized SDK and matched the wiper's targeting criteria is at risk of irreversible data loss.

## C2 Infrastructure

The exfiltration channel uses the open-source Session messenger network (`getsession.org`), a Signal-fork that runs over a decentralized onion-routed Service Node network. The campaign uses two named hosts:

- `filev2.getsession.org` — File-server dead-drop. Encrypted credential bundles are uploaded here. - `seed1.getsession.org` — Seed/coordination node. Used for bootstrap and configuration.

Session traffic is HTTPS-tunneled and difficult to distinguish from legitimate messaging traffic without explicit allow-listing. Egress-control environments that do not allow outbound to `*.getsession.org` will block exfiltration; environments that allow it (developer endpoints, dev/test cloud accounts, ephemeral CI runners) are exposed.

## Persistence on Developer Endpoints

Where the dropper detects a developer endpoint (presence of VS Code workspace files, presence of `.claude/` directories), the second-stage writes persistence into the AI coding agent surface — the same vector first documented in the TanStack May 11 wave:

- `~/.claude/settings.json` — Anthropic Claude Code agent settings; the worm injects a malicious agent task that re-fires on next agent launch. - `.vscode/tasks.json` — VS Code workspace task definitions; the worm injects a task that re-fires when the workspace is opened.

These persistence vectors survive credential rotation and survive package removal, because they live in the user's home directory and the project workspace rather than in the package itself.

## Attribution

Attribution to TeamPCP rests on toolchain reuse across the Mini Shai-Hulud lineage (PBKDF2 salt strings, encrypted-bundle format, Session dead-drop addresses, persistence vectors), the operator's `"Love - TeamPCP"` README signature in the leaked framework source, and the temporal/coordinated nature of the W21 escalation (the durabletask publish on 2026-05-19 coincided with the @antv npm wave and was 24 hours after the Nx Console v18.95.0 publish that breached GitHub-internal). Mandiant / Google Threat Intelligence Group has not (as of 2026-05-25) issued a named-actor product on UNC6780 covering this incident. Microsoft publicly entered the response coalition; CISA has not added CVE-2026-45321 (the TanStack OIDC abuse chain that bridges Nx Console to TeamPCP) to the Known Exploited Vulnerabilities catalog in either of the two W21 update tranches.

## Affected Surface

Any environment that executed `pip install durabletask` resolving to 1.4.1, 1.4.2, or 1.4.3 on 2026-05-19 — or whose lockfile pinned one of those versions — is exposed. This includes ephemeral CI runners that ran a single `pip install` step. The import-time trigger means hosts that resolved to one of those versions and then never imported the package are at lower risk, but Azure Functions Python runtimes import the SDK at function-app startup, so any Functions deployment that pulled an affected version is at maximum exposure.

## Detection Surface

Durable behavioral indicators (preferred over framework artifacts, which now also fire on copycat forks of the leaked Shai-Hulud source):

- Writes to `~/.claude/settings.json` and `.vscode/tasks.json` from non-interactive processes. - Outbound DNS or HTTPS to `*.getsession.org` from server, CI, or container workloads. - Python processes invoking `aws ssm send-command` or `kubectl exec` against peer instances within the same cloud account or cluster. - IMDSv2 / Azure IMDS / GCE metadata enumeration from a Python process that just installed or imported `durabletask`. - 2FA-bypassing token-harvest patterns (large-scale enumeration of `~/.aws/credentials`, `~/.azure`, `~/.config/gcloud`, Vault token files, 1Password / Bitwarden CLI session tokens within a short time window from a single process).

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

Collection

T1005 Data from Local System; T1530 Data from Cloud Storage

Lateral Movement

T1021.007 Remote Services: Cloud Services

Defense Evasion

T1027 Obfuscated Files or Information; T1036.005 Match Legitimate Resource Name or Location; T1070.004 Indicator Removal: File Deletion

Exfiltration

T1048 Exfiltration Over Alternative Protocol; T1567 Exfiltration Over Web Service

Execution

T1059.006 Command and Scripting Interpreter: Python; T1204.002 User Execution: Malicious File

Command and Control

T1071.001 Application Layer Protocol: Web Protocols; T1105 Ingress Tool Transfer; T1573.001 Encrypted Channel: Symmetric Cryptography

Initial Access

T1078.004 Valid Accounts: Cloud Accounts; T1195 Supply Chain Compromise; T1195.002 Compromise Software Supply Chain

Discovery

T1082 System Information Discovery; T1580 Cloud Infrastructure Discovery; T1613 Container and Resource Discovery

Impact

T1485 Data Destruction; T1561 Disk Wipe

Credential Access

T1528 Steal Application Access Token; T1539 Steal Web Session Cookie; T1552.001 Unsecured Credentials: Credentials In Files; T1552.005 Unsecured Credentials: Cloud Instance Metadata API; T1555 Credentials from Password Stores

Persistence

T1546 Event Triggered Execution

stealth

T1574 Hijack Execution Flow

Resource Development

T1586 Compromise Accounts; T1587.001 Develop Capabilities: Malware

execution

T1609 Container Administration Command

Affected products and versions in durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

  • Microsoft — durabletask (Azure Durable Functions Python SDK)
    Vulnerable versions: 1.4.1; 1.4.2; 1.4.3
    Fixed in: <1.4.1 (e.g., 1.4.0); post-incident re-issued version
  • Microsoft — Azure Functions Python Runtime (transitive consumer of durabletask)
    Vulnerable versions: any deployment that resolved durabletask 1.4.1–1.4.3 on 2026-05-19
    Fixed in: rebuilt deployments using a non-affected durabletask version

Remediation for durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

Patches

  • Upgrade durabletask to a known-good version: any version <1.4.1 or any version published after Microsoft re-issued the SDK post-incident; verify the package's source files match the upstream GitHub release tag SHA.
  • If using Azure Functions Python runtime: rebuild and redeploy all function apps that pulled an affected durabletask version; recycle managed identities.

Immediate actions

  • Inventory all environments that installed durabletask versions 1.4.1, 1.4.2, or 1.4.3 from PyPI on 2026-05-19 — include ephemeral CI runners, container-image build layers, and Azure Functions Python deployments.
  • Treat any host that imported one of those versions as fully compromised: assume cross-cloud credential theft (AWS, Azure, GCP, Vault, 1Password, Bitwarden) and assume worm propagation via AWS SSM and kubectl exec.
  • Rotate all credentials reachable from affected hosts: AWS keys and IAM-role session tokens, Azure tokens and Managed Identity tokens, GCP ADC and service-account tokens, HashiCorp Vault tokens, 1Password and Bitwarden vault session tokens, GitHub PATs, npm granular access tokens, SSH keys, Kubernetes service-account tokens, Stripe API keys.
  • Block outbound HTTPS and DNS to `*.getsession.org` from server, CI, and container egress points.
  • Audit AWS SSM session history (`ssm:DescribeSessions`, `ssm:GetCommandInvocation`) and Kubernetes audit logs (`pods/exec`) for the 72-hour window following 2026-05-19 against any host that may have run an affected durabletask version.

Workarounds

  • Hold all durabletask deployments at the last known-good version (e.g., 1.4.0) and pin in requirements/constraints files until the incident response window closes.
  • Block `durabletask` versions 1.4.1, 1.4.2, and 1.4.3 in your private PyPI mirror's deny-list.

Longer-term hardening

  • Pin exact versions of all dependencies in production and CI lockfiles; verify lockfile hashes against a known-good baseline; do not rely on publisher-verified or attestation badges as install-time safety signals.
  • Deploy a private PyPI mirror with allow-list + delay window so that newly-published versions are quarantined before they can enter build systems.
  • Constrain IMDSv2 hop limits on EC2 to 1 so application processes cannot reach the metadata service from container workloads.
  • Scope AWS SSM permissions tightly: deny `ssm:SendCommand` from application IAM roles; restrict to a small set of operator roles.
  • Scope Kubernetes service-account permissions: deny `pods/exec` and `pods/portforward` to application service-accounts; restrict to operator-only RBAC bindings.
  • Monitor and alert on writes to `~/.claude/settings.json` and `.vscode/tasks.json` from non-interactive processes; this is the durable Mini Shai-Hulud persistence vector.

CVEs associated with durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

CVE-2026-45321

Weaknesses (CWE) in durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

CWE-1357, CWE-506, CWE-829, CWE-494, CWE-913

Timeline of durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

  • TeamPCP TanStack npm wave harvests OIDC credentials; root of the credential-to-publish chain later used in the W21 escalations (tracked as CVE-2026-45321).
  • TeamPCP publishes trojanized Nx Console v18.95.0 to the Visual Studio Marketplace using credentials traced to the TanStack wave; live for ~18 minutes; breaches GitHub-internal CI/CD and exfiltrates ~3,800 internal repos.
  • iTnews reporting characterizes the durabletask second stage as carrying a Linux disk wiper — first publicly reported destructive payload in the Mini Shai-Hulud lineage without locale gating.
  • Wiz, Aikido, and Endor Labs publish independent analyses of the durabletask trojanization; identify import-time execution, cross-cloud credential stealer, AWS SSM and kubectl exec worm propagation.
  • In parallel, TeamPCP publishes the @antv npm wave (639 malicious versions across 323 packages) via compromised maintainer account "atool" — same operator, same day.
  • All three malicious versions (1.4.1, 1.4.2, 1.4.3) yanked from PyPI within an approximately 35-minute total compromise window from first publish to last yank.
  • durabletask v1.4.3 published — third trojanized version in the same window.
  • durabletask v1.4.2 published — second trojanized version in the same window.
  • TeamPCP publishes durabletask v1.4.1 to PyPI using compromised Microsoft maintainer credentials; first trojanized version goes live.
  • GitHub CISO Alexis Wales publicly names Nx Console v18.95.0 as the root of the GitHub-internal breach; confirms OpenAI, Grafana Labs, and Mistral AI as downstream victims; ties Nx Console publish credential back to the TanStack OIDC chain.
  • Datadog Security Labs, ReversingLabs, and OX Security report that the complete TeamPCP Shai-Hulud framework source has been published to GitHub; copycat forks observed within hours, including one adding FreeBSD support.
  • CISA completes the two W21 Known Exploited Vulnerabilities update tranches without adding CVE-2026-45321 despite the GitHub-internal breach and the durabletask trojanization.
  • SANS ISC publishes comprehensive W21 TeamPCP campaign brief (Kenneth Hartman); Threadlinqs Intelligence opens TL-2026-0580 for the durabletask incident specifically.
  • As of 2026-05-29, the trojanized durabletask versions (1.4.1-1.4.3) were yanked from PyPI within hours on 2026-05-19 and Microsoft rotated tokens (safe at 1.4.0), so the specific package vector is contained. But operator TeamPCP remains highly active with ongoing waves and open-sourced copycats, and CISA added the campaign CVE-2026-45321 to its KEV catalog on 2026-05-27.

Sources cited for durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

Threats related to durabletask PyPI Supply Chain Compromise (v1.4.1–1.4.3)

Detection coverage for TL-2026-0580

As of 2026-05-25, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-0580 across Splunk SPL, Microsoft KQL and Sigma, covering 25 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