← Back to blog
supply chainPyPIsmall businessremediation

Another PyPI Package Was a Trojan Horse. This One Had a Wiper.

Microsoft's official Durable Task Python SDK was hijacked on PyPI with a credential stealer, a Linux file wiper, and worm logic that spreads using your own cloud keys. No CVE was assigned. Most scanners missed it.

Darius J Davis · May 18, 2026

#You trust packages because someone you trust published them.

That's the deal. You install a package from PyPI or npm because a reputable maintainer or organization published it. You don't read the source code. You don't diff version 1.4.0 against 1.4.1. You run pip install and move on with your day. Everyone does.

On May 19, 2026, someone used a compromised maintainer's PyPI token to publish three malicious versions of durabletask, the official Python SDK for Microsoft's Durable Task Framework. Versions 1.4.1, 1.4.2, and 1.4.3 were uploaded within a 35-minute window. All three carried a multi-stage payload that activates on import.

This wasn't a typosquat. This wasn't a lookalike package with a similar name. This was the real package, from the real namespace, published with a real token stolen from a real maintainer's compromised device.

#Credential stealer. File wiper. Worm.

The malicious versions fetch and execute a second-stage payload the moment your code imports the package. That payload does three things:

It steals credentials. Cloud provider keys, developer tool tokens, environment variables. Anything reachable from the process that imported the package gets harvested and exfiltrated.

It wipes files on Linux. The payload includes a destructive component targeting Linux hosts. Not ransomware asking for payment. A wiper. It deletes your data. CI/CD runners, development servers, production hosts running Linux -- all potential targets.

It spreads. The payload contains worm-like logic that uses the credentials it just stole to move laterally through your cloud infrastructure. It harvests your cloud keys, then uses those keys to reach other systems. One compromised developer workstation becomes a launchpad into your AWS account, your staging environment, your production cluster.

All three versions were quarantined by PyPI, but they were live and installable for a window of time. And durabletask is the kind of dependency that gets pulled in transitively. Your team might not even know they depend on it. A CI/CD pipeline that runs pip install --upgrade during a build could have pulled one of these versions automatically with zero human involvement.

#No CVE. Your scanner didn't catch it.

Here's what makes this one particularly insidious: no CVE was ever assigned.

Most vulnerability scanning tools -- the ones your security team relies on, the ones running in your CI pipeline, the ones your compliance auditor asks about -- work by matching installed packages against a database of known CVEs. No CVE means no match. No match means no alert. Your scanner ran, found nothing, and gave you a green checkmark while a credential stealer was executing in your build pipeline.

This is the gap between "we scan for vulnerabilities" and "we're actually secure." CVE-based scanning catches known vulnerabilities in legitimate software. It was never designed to catch supply chain compromises where the package itself is the attack. If your entire security posture depends on CVE feeds, you have a blind spot the size of the entire package registry.

#This keeps happening.

If this story sounds familiar, it should. We've been covering this pattern all year.

In May, node-ipc was backdoored through an expired domain -- a $12 domain registration gave an attacker publish access to a package with 10 million weekly downloads. The credential stealer in that attack exfiltrated secrets via DNS queries, bypassing most network monitoring entirely.

The TeamPCP campaign has been even worse. Seven waves, 170+ compromised packages, including TanStack (12 million weekly downloads), a VS Code extension with 2.2 million installs, a Checkmarx Jenkins plugin (a security scanner carrying malware), and PyTorch Lightning. They breached GitHub's internal repositories through a compromised VS Code extension. Their worm spreads across npm and PyPI simultaneously using stolen registry tokens.

The durabletask compromise fits the same pattern. A legitimate maintainer's credentials were stolen from a previously compromised device. Those credentials were used to publish malicious versions of a trusted package. The payload harvests more credentials to enable further attacks. It's the same playbook, run against a different target, in a different package registry.

The supply chain is a worm that feeds itself.

#What this means for your business.

Your developers install packages. That's not optional. Modern software development depends on open-source libraries. Your Python backend, your data pipeline, your internal tooling -- all of it pulls dependencies from PyPI. If your team runs Python, they're in the blast radius.

Your SaaS vendors install packages too. The workflow automation tool you use, the data analytics platform, the internal dashboard. Their developers are running pip install just like yours. If one of their dependencies was compromised, the malicious code ships in their next release, and you receive it as a routine software update.

And this isn't theoretical. The durabletask compromise included a wiper. Not "we might steal some data." Destruction. Files deleted. If that hit a production system or a CI/CD runner with access to your infrastructure, you're doing incident response, not just rotating credentials.

#What to do.

If you use durabletask (directly or transitively):

  1. Check your lockfiles and CI logs for versions 1.4.1, 1.4.2, or 1.4.3. Search requirements.txt, poetry.lock, Pipfile.lock, and any pip install logs from your CI/CD pipelines for the week of May 19. If any of those versions were installed, that environment is compromised.
  1. If a compromised version ran anywhere, treat that host as breached. Rotate every credential that host could reach: cloud provider keys, database passwords, API tokens, service account credentials. Check for unauthorized access using those credentials. This is incident response, not just a package update.
  1. Pin to version 1.4.0 (the last known-clean release) or a verified later release once Microsoft confirms the package is clean.

For everyone managing Python projects:

  1. Use lockfiles. If you're installing packages with pip install without a pinned lockfile, you're trusting that every new version of every transitive dependency is clean. Use pip-compile (from pip-tools), Poetry, or PDM to generate and commit lockfiles that pin exact versions.
  1. Audit your dependencies for supply chain attacks, not just CVEs. Tools like Socket.dev and Snyk detect suspicious package behavior -- unexpected network access, install scripts, obfuscated code -- that CVE scanners miss entirely. This attack had no CVE. Your CVE scanner would have smiled and waved it through.
  1. Generate a Software Bill of Materials (SBOM). You need a complete inventory of every package in every project, including transitive dependencies. When the next supply chain compromise drops, you need to answer "are we affected?" in minutes, not days. Tools like Syft and CycloneDX generate SBOMs from your lockfiles and container images.
  1. Enforce MFA on your PyPI publishing accounts. PyPI supports it. If your team publishes packages, a stolen token without MFA is all an attacker needs to turn your package into the next trojan horse.
  1. Review what your CI/CD pipelines can reach. If your build runner has production cloud credentials, a compromised dependency in your build process has production cloud credentials too. Apply least privilege. Your test pipeline doesn't need your production AWS keys.

~/teampcp/shai-hulud · supply chain worm

#Further reading

Share this article
LinkedInX / TwitterEmail

Ready to secure your business?

Free 30-minute consultation. No sales script.

Call (773) 417-9994