devtake.dev

Mini Shai-Hulud hit PyTorch Lightning. The 11.6M-download PyPI package shipped a credential stealer.

Two malicious lightning releases hit PyPI on April 30. The 42-minute window was enough to ship an RSA-encrypted infostealer to ML developers worldwide.

Luca Reinhardt · · 4 min read · 5 sources
Lightning AI logo on a dark background, illustrating the PyPI supply chain compromise of the lightning Python package.
Image: lightning.ai · Source

PyPI quarantined the Lightning Python package on April 30 after two releases shipped a credential stealer hidden under a _runtime directory. The package is the umbrella distribution for PyTorch Lightning, the framework with 11.6 million monthly downloads that backs much of the ML training stack.

Versions 2.6.2 and 2.6.3 stayed live for 42 minutes before Socket’s AI scanner flagged them and PyPI pulled the listings. That’s not nothing in a global registry. A 42-minute window catches every CI job that ran pip install lightning while the bad versions were the latest, plus every developer who happened to refresh their training environment that morning. Lightning AI rotated the package back to the safe 2.6.1 and started a credential-rotation drill with anyone who can prove they pulled the bad release.

What the malicious release actually did

The payload was a textbook Mini Shai-Hulud variant. On import, Lightning quietly downloaded the Bun JavaScript runtime from GitHub, then used Bun to execute an obfuscated 11 MB credential stealer. Bun is fine software. It’s also a clever way to avoid a Python sandbox: ship a JS payload, run it on a runtime that wasn’t part of the PyPI security review, and you’ve sidestepped half the static analysis.

The stealer scans for SSH keys, shell history, .env files, git credentials, AWS/GCP/Azure metadata, crypto wallets, VPN configs, and Discord and Slack session tokens. According to Aikido Security’s writeup, it RSA-2048 encrypts the haul before exfiltrating to public GitHub repositories. That’s the same dead-drop pattern the Bitwarden CLI compromise used in April, which makes attribution easy and remediation hard. By the time an organization scrubs the leak repo, the data is already mirrored.

Stage two is the worm part. With a stolen GitHub token in hand, the stealer commits backdoor files into every repo the token can reach, authoring commits as [email protected] to impersonate Claude Code’s bot identity. Stage three rummages for local .tgz tarballs, injects malicious postinstall hooks, bumps the version, and waits for the developer to ship the next npm release.

How the attacker got in

This is the part that should worry anyone running an ML platform. The GitHub repository was not breached. Source control still shows clean history. Socket’s analysis points to a project-scoped PyPI token: “The successful lightning upload likely came through a separate PyPI credential path, probably a project-scoped PyPI token.” A separate compromise of the pl-ghost GitHub account was used for lateral probing, but the actual poisoned tarball was published straight to PyPI, bypassing every protection that lives in CI.

Project-scoped tokens are a sensible feature. They’re also the highest-value secret in a maintainer’s wallet, and the registry has no clean way to verify that a tarball published with one matches the source tree on GitHub. Sigstore-backed PyPI Trusted Publishers close that gap, but only for projects that have actually opted in.

What this means for you

If your ML environment touched lightning==2.6.2 or 2.6.3 between roughly 14:00 and 14:42 UTC on April 30, treat the host as compromised. Rotate every GitHub PAT, npm token, cloud key, and SSH key it had access to. Check your CI runner logs for outbound traffic to GitHub repositories with names that don’t belong to you, and audit your last-week of npm publishes for unexpected postinstall hooks. The malware’s self-propagation step means the blast radius isn’t bounded by Python. Anything you push afterward can drag the worm into a teammate’s machine.

For the longer-term fix, pin ML dependencies by hash and turn on PyPI Trusted Publishers for any package you maintain. The next attack will take 42 minutes too, and the only durable defense is making project-scoped tokens worthless on their own.

Share this article

Quick reference

PyPI
The Python Package Index, the default registry pip pulls from. About 12 billion package downloads a month, and historically the soft target for supply-chain attacks against ML stacks.
Mini Shai-Hulud
A credential-stealing supply-chain campaign first seen on npm in early 2026. The 'mini' fork drops the worming through dependents but keeps the credential exfil and repo backdooring.

Sources

Mentioned in this article