The AI Framework Trojan: How PyTorch Lightning's PyPI Compromise Became the Most Dangerous Supply Chain Attack of 2026
TL;DR: On April 30, 2026, two malicious versions of lightning — the PyPI package for the PyTorch Lightning deep learning framework — were published and remained live long enough to reach a significant developer population before PyPI quarantine. Versions 2.6.2 and 2.6.3 contained a hidden _runtime directory shipping a Python downloader and an 11 MB obfuscated JavaScript credential stealer that executed automatically on import lightning. The attack is attributed to the Mini Shai-Hulud threat actor — the same group that compromised four SAP npm packages the previous day — and represents a deliberate escalation: moving from niche enterprise packages to one of the top-50 most downloaded AI libraries in the Python ecosystem.
Background: What Is PyTorch Lightning and Why Does It Matter?
PyTorch Lightning is not a toy. Born as a productivity wrapper around raw PyTorch, it has become the de facto training harness for organizations running serious ML workloads — fine-tuning LLMs, training diffusion models, building image classifiers, running production forecasters. The lightning package on PyPI logged 311,027 downloads per day at time of compromise, with 2,051,273 weekly and 7.9 million monthly downloads. The legacy pytorch-lightning distribution (a separate, still-installable package) adds another 436,296 daily downloads. The project has 31,100 GitHub stars.
This is not a fringe package targeted for obscurity. This is the beating heart of AI model development infrastructure at enterprise scale. Compromising it is equivalent to poisoning the water supply for ML pipelines everywhere.
The last clean version — 2.6.1 — was published January 30, 2026. A gap of exactly three months elapsed before the attacker published 2.6.2 on April 30, 2026, followed shortly by 2.6.3 on the same day. This multi-version release mimics legitimate patch cadence and would have deceived most dependency monitoring tools checking only for "latest stable."
Technical Analysis
Stage 0: The Delivery Mechanism — Wheel Poisoning
The attack used a standard PyPI wheel (.whl) poisoning technique. The lightning-2.6.3-py3-none-any.whl file (SHA-256: 56070a9d8de0c0ffb1ec5c309953cf4679432df5a78df9aeb020fbb73d2be9fb) preserved all legitimate Lightning library files. Every import works. Every test passes. The framework runs exactly as expected — because the payload is additive, not destructive. The malicious additions live entirely in a hidden _runtime/ directory injected into the wheel archive, containing two files.
_runtime/start.py (SHA-256: 8046a11187c135da6959862ff3846e99ad15462d2ec8a2f77a30ad53ebd5dcf2) — A thin Python downloader, 40-60 lines. Its sole job is to fetch the Bun JavaScript runtime binary (version 1.3.13, specifically, from https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/) and then execute the stealer payload under it. Critically, this script is injoked from Lightning's __init__.py via a patched import hook, meaning the payload fires the instant any Python process executes import lightning — including automated CI pipelines that never run user-facing code.
_runtime/router_runtime.js (SHA-256: 5f5852b5f604369945118937b058e49064612ac69826e0adadca39a357dfb5b1) — The actual stealer. Approximately 11 MB as a single-line obfuscated JavaScript file. The obfuscation uses javascript-obfuscator-style string-array rotation with a secondary cipher function named __decodeScrambled(). The decryption implementation uses PBKDF2/SHA-256 with 200,000 iterations and the salt string ctf-scramble-v2.
That cipher — the function name, the algorithm, the salt, and the iteration count — is identical to the cipher recovered from the Checkmarx and Bitwarden CLI compromises earlier in 2026. This is the most definitive technical attribution link: it is functionally impossible that two separate threat actors independently implemented the same custom cipher with the same hardcoded salt.
Stage 1: Credential Harvesting — 80+ File Paths, Four Exfil Channels
The stealer operates across four parallel exfiltration channels simultaneously. This design ensures stolen data reaches the attacker even if individual network paths are blocked:
Channel 1 — HTTPS POST to C2. Stolen data is immediately posted to an attacker-controlled server over port 443. The C2 domain and path are stored as encrypted strings in the payload, making static analysis harder without full deobfuscation of the 11 MB blob.
Channel 2 — GitHub Commit Search Dead-Drop. The malware polls the GitHub commit search API for commit messages prefixed with EveryBoiWeBuildIsAWormyBoi. These commits carry double-base64-encoded tokens in the format EveryBoiWeBuildIsAWormyBoi:<encoded_token>. Once decoded, the token is used to authenticate an Octokit client for further operations. This channel is clever: it uses GitHub's own infrastructure as a command-and-control relay, meaning all traffic goes to api.github.com and appears legitimate in network logs.
Channel 3 — Attacker-Controlled Public GitHub Repos. The malware creates a new public GitHub repository with a randomly chosen Dune-universe name and the description "A Mini Shai-Hulud has Appeared" (directly searchable on GitHub). Stolen credentials are committed as results/results-<id>-<timestamp>.json, base64-encoded via API (plain JSON inside), with files over 30 MB split into numbered chunks. Commit messages use chore: update dependencies as cover.
Channel 4 — Push to Victim's Own Repo. If the malware obtains a ghs_ GitHub server token (Actions runner token), it pushes stolen data directly to up to 50 branches of the victim's own $GITHUB_REPOSITORY.
The harvested credential targets include:
- Filesystem: 80+ credential file paths scanned for
ghp_,gho_, andnpm_tokens (up to 5 MB per file) - Shell/Environment:
gh auth tokenexecution + fullprocess.envdump - GitHub Actions: On Linux runners, Python-based memory dump of
Runner.Workerprocess to extract secrets marked"isSecret":true, plusGITHUB_REPOSITORYandGITHUB_WORKFLOW - AWS: Environment variables,
~/.aws/credentialsprofiles, IMDSv1/v2 instance metadata - Cloud Secrets: GCP, Azure, Doppler, Vault tokens via standard credential file locations
Stage 2: GitHub Repository Poisoning — The Claude Impersonation
When a valid GitHub token is found, the malware injects a worm-like payload into up to 50 branches of every accessible repository. The injection operation is an upsert: files that do not exist are created; files that do exist are silently overwritten without pre-checking existing content.
The most alarming element of this stage: every poisoned commit is authored using a hardcoded identity designed to impersonate Anthropic's Claude Code. The commit author name and email match the Claude Code agent identity pattern, meaning in a busy repository's git log, malicious commits would appear to be routine AI assistant contributions. In a world where Claude Code is widely used for automated code generation and maintenance commits, this impersonation is devastatingly plausible.
Stage 3: The npm Worm — Cross-Ecosystem Propagation
If the victim's environment contains npm publish credentials, the malware executes an npm-based propagation vector:
1. Modifies all local npm packages the token can publish to
2. Injects a setup.mjs dropper and router_runtime.js into each package
3. Sets scripts.preinstall in package.json to execute the dropper on install
4. Bumps the patch version number automatically
5. Repacks .tgz tarballs
6. Republishes all modified packages to npm under the legitimate maintainer's account
Any downstream developer who subsequently runs npm install <affected-package> receives the full stealer on their machine, which then steals their tokens, worms their packages, and propagates to the next hop. This is an ecosystem-jumping worm: it enters through PyPI, replicates through npm, and can re-enter PyPI if the environment has both Python and Node.js credentials.
Attribution: Mini Shai-Hulud Threat Actor
Multiple independent analysis teams (Socket, Semgrep, Snyk, Aikido, OX Security, StepSecurity) assess this campaign as the work of the Mini Shai-Hulud threat actor — the same group responsible for compromising four SAP-ecosystem npm packages on April 29, 2026.
The attribution confidence is high based on:
- Identical cipher implementation:
__decodeScrambled()with PBKDF2/SHA-256, 200K iterations, saltctf-scramble-v2 - Identical Bun version: Bun v1.3.13 loader across all known Mini Shai-Hulud samples
- Dune-themed naming convention:
EveryBoiWeBuildIsAWormyBoiprefix (distinct from the originalmini-shai-huludprefix, suggesting intentional versioning of the campaign) - Same exfiltration architecture: Four-channel design with GitHub commit search dead-drop
- Same payload size/obfuscation class: ~11 MB single-line JavaScript, javascript-obfuscator-style
The Dune-universe branding is consistent, deliberate, and serves as an operational signature. The threat actor is either unconcerned about attribution or using the branding as a distraction — either way, the pattern provides defenders with strong detection hooks.
The initial access vector for the lightning package is still under investigation. The most probable hypothesis is a developer account compromise (phishing, credential stuffing, or session token theft), as the malicious versions were published through the legitimate Lightning-AI PyPI publisher account. No public vulnerability in PyPI's publish pipeline has been identified.
Timeline
| Time (UTC) | Event |
|---|---|
| April 29, 2026 | Mini Shai-Hulud compromises SAP npm packages; same Bun/cipher toolchain |
| April 30, 2026 ~00:xx | lightning 2.6.2 published to PyPI with malicious _runtime/ payload |
| April 30, 2026 ~00:18 | Socket AI scanner flags 2.6.2 as potentially malicious (18 minutes post-publish) |
| April 30, 2026 | lightning 2.6.3 published — second wave, same payload |
| April 30, 2026 | GitHub issue #21689 "Possible supply chain attack on version 2.6.3" opened, later closed without public explanation |
| April 30, 2026 | Socket, Aikido, Semgrep, Snyk, OX Security, StepSecurity all publish simultaneous advisories |
| April 30, 2026 | PyPI quarantines the lightning project; pypi.org/pypi/lightning/json returns HTTP 404 |
| May 1, 2026 | PyPI quarantine lifted; versions 2.6.2 and 2.6.3 deleted; 2.6.1 restored as latest |
| May 2, 2026 | Ongoing: Lightning-AI investigation into maintainer account compromise continues |
Indicators of Compromise (IOCs)
File Hashes
| File | SHA-256 |
|---|---|
| _runtime/start.py | 8046a11187c135da6959862ff3846e99ad15462d2ec8a2f77a30ad53ebd5dcf2 |
| _runtime/router_runtime.js | 5f5852b5f604369945118937b058e49064612ac69826e0adadca39a357dfb5b1 |
| lightning-2.6.3-py3-none-any.whl | 56070a9d8de0c0ffb1ec5c309953cf4679432df5a78df9aeb020fbb73d2be9fb |
Behavioral IOCs
- Presence of
_runtime/directory inside any Python package wheel - Any Python process spawning a Bun runtime binary download from
github.com/oven-sh/bun/releases/ - GitHub API calls to
/search/commitswith query strings containingEveryBoiWeBuildIsAWormyBoi - Public GitHub repositories with description
"A Mini Shai-Hulud has Appeared" - Git commits authored with Anthropic/Claude Code identity patterns not matching known project contributors
- Unexpected
.claude/or.vscode/directories with binary or obfuscated content in repositories npmpackage tarball modifications with injectedsetup.mjsandscripts.preinstallhooks- Network connections to port 443 with PBKDF2-encrypted payloads immediately following
import lightning
Affected Package Versions
lightning==2.6.2(PyPI) — MALICIOUS, deletedlightning==2.6.3(PyPI) — MALICIOUS, deletedlightning==2.6.1(PyPI) — CLEAN (last known safe version)pytorch-lightning(separate package) — UNAFFECTED
Snyk Advisory
SNYK-PYTHON-LIGHTNING-16323121— CVSS 4.0: 9.3 Critical — CWE-506 (Embedded Malicious Code)
Lyrie Take: The AI Toolchain Is the New Crown Jewel
The Mini Shai-Hulud campaign's pivot to AI framework packages is not accidental. It reflects a calculated threat intelligence assessment: AI development environments are among the most credential-rich environments on the planet.
A typical ML engineer's workstation or CI runner will have, simultaneously: GitHub tokens with broad repository write access, AWS/GCP/Azure credentials for GPU cloud training, Hugging Face API keys, Weights & Biases tokens, Docker registry credentials, and often SSH keys for production inference infrastructure. The AI pipeline is a credential aggregator by design — and until now, the security community has largely treated it as separate from the "real" attack surface.
The three-month gap between clean version 2.6.1 and the malicious 2.6.2 deserves scrutiny. This is consistent with a threat actor who:
1. Obtained maintainer credentials well in advance
2. Waited patiently to reduce suspicion
3. Chose the timing deliberately — April 30 is a Thursday, when many security teams are in a pre-weekend attention dip
The Claude Code impersonation is the most provocative element of this attack. It targets the mental model that AI-generated commits are routine and trustworthy. As AI coding assistants become standard infrastructure, the social engineering attack surface of "this commit looks like an AI made it" expands dramatically. The attacker here was not just stealing credentials — they were poisoning the trust model for AI-assisted development.
Lyrie's autonomous defense approach is particularly relevant here. Human SOC teams cannot review 311,000 daily package downloads for behavioral anomalies. Automated behavioral analysis of wheel contents at install time, combined with supply chain graph monitoring for unexpected new versions from long-dormant publishers, is the only scalable defense.
Defender Playbook
Immediate Actions (if lightning 2.6.2 or 2.6.3 was ever installed):
1. Rotate all credentials present in the affected environment: GitHub tokens (ghp_, gho_, ghs_), npm tokens (npm_), AWS keys, GCP service account keys, Azure credentials, Hugging Face API keys, Doppler secrets, Vault tokens
2. Audit git repositories accessible by the environment's GitHub tokens for unexpected commits authored by Claude Code / Anthropic identities from the April 30 window
3. Scan npm packages the developer can publish for unexpected setup.mjs, router_runtime.js, or scripts.preinstall hooks
4. Search GitHub for repositories created by the compromised account with Dune-themed names
5. Check GitHub Actions secrets — if the environment ran in Actions, assume all isSecret:true secrets were exfiltrated
6. Review .claude/ and .vscode/ directories in all accessible repositories for unexpected binary or obfuscated content
Detection Rules:
# YARA — detect Bun loader pattern in Python wheels
rule MiniShaiHulud_BunLoader {
strings:
$runtime_dir = "_runtime/" ascii
$bun_download = "bun/releases/download/bun-v" ascii
$decode_fn = "__decodeScrambled" ascii
$salt = "ctf-scramble-v2" ascii
condition:
2 of them
}
# Sigma — GitHub API commit search for C2 dead-drop
title: Mini Shai-Hulud C2 Dead-Drop via GitHub Commit Search
detection:
selection:
http.url|contains: "api.github.com/search/commits"
http.request.body|contains: "EveryBoiWeBuildIsAWormyBoi"
condition: selection
Preventive Controls:
- Pin AI framework dependencies to specific, audit-verified versions (not
lightning>=2.6.0); use hash pinning inrequirements.txt - Implement
--require-hashesin pip install for all CI pipelines - Add behavioral scanning (Socket, Semgrep SCA, Snyk) to every PyPI install in CI — detection was available within 18 minutes of publish; CI pipelines running hours later could have caught this
- Monitor for unexpected Bun runtime downloads from GitHub in all developer and CI environments
- Block
github.com/oven-sh/bun/releases/downloads in environments that do not explicitly use Bun - Implement outbound network monitoring for CI runners; ML training environments should not be making unexpected HTTPS connections during
importphase - Tag all AI framework packages (PyTorch, TensorFlow, JAX, Lightning, Hugging Face) as high-criticality in dependency monitoring SLAs — the attack surface is too large for standard update cadence
Sources
1. Socket Research Team, "lightning PyPI Package Compromised in Supply Chain Attack," April 30, 2026 — https://socket.dev/blog/lightning-pypi-package-compromised
2. The Hacker News, "PyTorch Lightning and Intercom-client Hit in Supply Chain Attacks to Steal Credentials," May 1, 2026 — https://thehackernews.com/2026/04/pytorch-lightning-compromised-in-pypi.html
3. Semgrep, "Shai-Hulud Themed Malware Found in the PyTorch Lightning AI Training Library," April 30, 2026 — https://semgrep.dev/blog/2026/malicious-dependency-in-pytorch-lightning-used-for-ai-training/
4. Snyk, "lightning PyPI Compromise: A Bun-Based Credential Stealer in Python," April 30, 2026 — https://snyk.io/blog/lightning-pypi-compromise-bun-based-credential-stealer/
5. StepSecurity, "lightning: Obfuscated JavaScript Credential Stealer Bundled in PyPI Wheel," April 30, 2026 — https://www.stepsecurity.io/blog/lightning-obfuscated-javascript-credential-stealer-bundled-in-pypi-wheel
6. Snyk Advisory SNYK-PYTHON-LIGHTNING-16323121, https://security.snyk.io/vuln/SNYK-PYTHON-LIGHTNING-16323121
7. Lightning-AI GitHub Security Advisory GHSA-w37p-236h-pfx3, https://github.com/Lightning-AI/pytorch-lightning/security/advisories/GHSA-w37p-236h-pfx3
8. PyPI Download Statistics via pypistats.org, https://pypistats.org/api/packages/lightning/recent
Lyrie.ai Cyber Research Division — Senior Analyst Desk
Lyrie Verdict
Lyrie's autonomous defense layer flags this class of exposure the moment it surfaces — no signature update required.