Mini Shai-Hulud, Miasma and Hades Worms Spread Through Malicious PyPI Wheels

· Original article ↗

Summary

Researchers identified 23 new malicious PyPI artifacts using startup hooks, trojanized native extensions, and staged JavaScript payloads to target developer and CI/CD secrets.

Key points

  • The new wave adds 23 malicious PyPI package-version artifacts, including bioinformatics, AI/MCP-themed, and typosquatted packages.
  • Some packages use executable .pth startup hooks; bioinformatics packages hide import-time execution in trojanized .abi3.so native extensions.
  • A langchain-core-mcp variant searches Python’s sys.path for a separate _index.js payload, then attempts to run it with Bun.
  • The Hades-family JavaScript stealer targets developer workstations and CI/CD environments for registry tokens, cloud credentials, SSH keys, Kubernetes material, and other secrets.
  • A fake prompt-injection header in a JavaScript comment appears intended to disrupt AI-assisted malware analysis; the article says it does not affect execution.
  • The campaign tracker lists 471 affected artifacts across npm and PyPI. Defenders are advised to check package versions and execution indicators, preserve evidence, and rotate potentially exposed credentials.

Article Details

Attack Vectors
  • Malicious PyPI wheels use executable *-setup.pth files to launch an obfuscated _index.js payload during Python startup, downloading Bun if needed.
  • Trojanized .abi3.so native extensions launch the JavaScript payload when Python imports the package and initializes the extension through dlopen(). The malicious trigger is not visible in the package's Python source files.
  • The langchain-core-mcp@1.4.2 wheel installs langchain_core-setup.pth without bundling _index.js. Its loader searches sys.path entries and their immediate subdirectories for the payload, then attempts to execute it with Bun.
  • Typosquat-style and AI/MCP-themed packages appear intended to attract developer installations alongside malicious versions of established research-community packages.
  • The JavaScript payload includes a fake instruction header intended to disrupt AI-assisted malware analysis, followed by obfuscated executable code.
  • The stealer targets developer workstations and CI/CD environments for registry tokens, cloud credentials, Kubernetes service account material, SSH keys, Docker configuration, shell histories, .env files, and AI developer tool configuration.
Defensive Notes
  • Check installed package versions against the affected-artifact list and preserve forensic artifacts before uninstalling where possible.
  • Rotate tokens and other credentials that may have been exposed, especially credentials available to build and release environments.
  • Inspect Python environments for executable .pth files, unexpected _index.js files, Bun download logic, and newly introduced .abi3.so extensions.
  • Review compiled native extensions rather than relying exclusively on Python source, setup scripts, metadata, or dependency declarations.
  • Do not assume the loader and JavaScript payload must reside in the same wheel; inspect payload discovery across Python import paths.
  • Inspect CI/CD runners for unusual workflow changes, Docker socket abuse, poisoned /etc/hosts entries, unexpected privileged containers, and access to package publishing credentials.
  • Treat file content supplied to AI-assisted analysis as untrusted data. The fake comment header does not prevent conventional static or behavioral analysis, including YARA rules, entropy checks, AST parsing, string extraction, and deobfuscation.
  • The article identifies agent.stepsecurity.io, api.stepsecurity.io, and app.stepsecurity.io as legitimate defensive-service domains reportedly blocked by the malware, not attacker infrastructure.

Indicators of compromise

TypeIndicatorContext
SHA2566506d31707a39949f89534bf9705bcf889f1ecae3dbc6f4ff88d67a8be3d01b2SHA256 of langchain_core-setup.pth, the malicious Python startup hook that searches for and launches a separate JavaScript payload.
SHA2566d332f814f15f19758d65026bbfd0a8c49671b319ec77b8fa1b27fc48afff7d9SHA256 of the malicious langchain_core_mcp-1.4.2-py3-none-any.whl loader artifact.

MITRE ATT&CK

Malware

Vendors

Products

BunInstead, it searches Python’s module search path, sys.path, for _index.js and attempts to run it with Bun.DockerGitHub, npm, PyPI, RubyGems, JFrog, cloud credentials, Kubernetes service account material, SSH keys, Docker configuration, shell histories, .env files, package registry credentials, and AI developer tooldreamgendreamgen@1.8.1embiggenpackages with lookalike and ecosystem-bait packages. The bioinformatics cluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages usedensmallenpackages with lookalike and ecosystem-bait packages. The bioinformatics cluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages used in graphGitHubthe malware targets developer workstations and CI/CD environments for high-value secrets, including GitHub, npm, PyPI, RubyGems, JFrog, cloud credentials, Kubernetes service account material, SSH keys, Dockergpseawith lookalike and ecosystem-bait packages. The bioinformatics cluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages used in graph learning,instructor-mcpinstructor-mcp@1.15.2langchain-core-mcpand MCP-themed packages, typosquat-style packages such as rsquests, tlask, and rlask, and a notable langchain-core-mcp loader variant that does not bundle the expected _index.js payload. Instead, it searches Python’smem8mem8@6.0.1mflux-streamlitmflux-streamlit@0.0.3npmmalware targets developer workstations and CI/CD environments for high-value secrets, including GitHub, npm, PyPI, RubyGems, JFrog, cloud credentials, Kubernetes service account material, SSH keys, Dockeropenai-mcpopenai-mcp@2.41.1orchestr8-platformorchestr8-platform@3.3.2phenopacket-store-toolkitand ecosystem-bait packages. The bioinformatics cluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages used in graph learning, patientppkt2synergypackages. The bioinformatics cluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages used in graph learning, patient phenotyping, phenopacketpyphetoolscluster, including embiggen, ensmallen, gpsea, phenopacket-store-toolkit, ppkt2synergy, and pyphetools, affects real packages used in graph learning, patient phenotyping, phenopacket tooling, and relatedPyPISocket Threat Research team identified a newer PyPI wave connected to the broader Mini Shai-Hulud, Miasma, and Hades supply chain attacks. This wave expands beyond the 37 malicious PyPI wheels covered in our weekendPythonloader variant that does not bundle the expected _index.js payload. Instead, it searches Python’s module search path, sys.path, for _index.js and attempts to run it with Bun.ray-mcp-serverray-mcp-server@0.2.1rlaska separate cluster of AI and MCP-themed packages, typosquat-style packages such as rsquests, tlask, and rlask, and a notable langchain-core-mcp loader variant that does not bundle the expected _index.js payload.rsquestspackages, a separate cluster of AI and MCP-themed packages, typosquat-style packages such as rsquests, tlask, and rlask, and a notable langchain-core-mcp loader variant that does not bundle the expectedtiktoken-mcptiktoken-mcp@0.13.1tlaskpackages, a separate cluster of AI and MCP-themed packages, typosquat-style packages such as rsquests, tlask, and rlask, and a notable langchain-core-mcp loader variant that does not bundle the expected _index.js

Tools

Industries

Related Articles