Open Source ·
Lightning PyPI wheel shipped Shai-Hulud stealer
lightning 2.6.2 and 2.6.3 bundled a hidden _runtime directory. Importing the package launched a Bun-backed JavaScript stealer tied to Mini Shai-Hulud.
On April 30, 2026, the Mini Shai-Hulud campaign reached Python machine-learning environments through lightning, the PyPI package behind PyTorch Lightning, a widely used training framework. Researchers at StepSecurity identified two malicious wheels, versions 2.6.2 and 2.6.3, and named 2.6.1 as the last known clean release.
The compromised wheels carried a hidden _runtime/ directory. Importing lightning spawned a daemon thread that downloaded the Bun JavaScript runtime from GitHub releases and executed _runtime/router_runtime.js, an obfuscated single-line payload large enough to hide most of its logic from any reviewer skimming the source tree. Running a JavaScript stealer from inside a Python ML package was the giveaway: the malware on PyPI was the same Bun-driven loader StepSecurity had been tracking on npm.
Once running, the payload harvested environment variables, cloud credentials, and GitHub tokens, used the GitHub API to move data off the host, and poisoned local npm tarballs so the same loader would propagate the next time the developer published a Node.js package. That made lightning both a stealer in its own right and a bridge from PyPI back into npm publishing paths.
The GitHub issue that first flagged the compromise was closed quickly with dismissive responses, which StepSecurity took as a sign that the attacker held some level of control over project accounts during the same window as the PyPI releases. This record stays scoped to the Lightning wheels; the wider Mini Shai-Hulud propagation pattern is tracked under the TeamPCP campaign.
Appendix · Affected releases
- StepSecurity identified 2.6.1 as the last known clean release.
- Hash order is the complete malicious lightning-2.6.2-py3-none-any.whl and lightning-2.6.3-py3-none-any.whl PyPI distributions. SafeDep publishes both archive-specific SHA-256 values separately from the embedded router_runtime.js, start.py, and __init__.py component hashes.
References
Source record: oss/attacks/pytorch-lightning/meta.yaml