All posts
Supply Chain Compromise

Lightning PyPI Hit: Mini Shai-Hulud Reaches AI Training

Two malicious lightning PyPI releases on April 30 stole CI credentials and weaponized AI coding agent configs as a persistence vector for the campaign

Securityv0 Intelligence Team OWASP: ASI06 sv0 finding: nhi_compromise
supply-chain nhi pypi shai-hulud ai-training claude-code

The Incident

On April 30, 2026, Lightning AI published GitHub Security Advisory GHSA-w37p-236h-pfx3 disclosing that two unauthorized releases of the lightning PyPI distribution — versions 2.6.2 and 2.6.3 — had been pushed to the index and contained credential-harvesting code. PyPI quarantined the malicious versions; Lightning AI confirmed 2.6.1 as the last known-good release. Independent analyses by Socket, Semgrep, Aikido, SafeDep, Wiz, OX Security, and Endor Labs describe code that executes on import, fetches the Bun JavaScript runtime, and exfiltrates discovered secrets — SSH keys, shell histories, cloud SDK credentials, and GitHub and npm tokens — by creating attacker-controlled GitHub repositories under the victim’s own account. Sophos, Dark Reading, StepSecurity, and Datadog Security Labs attribute the activity to a campaign tracked as “Mini Shai-Hulud,” a continuation of the TeamPCP cluster behind the March 2026 LiteLLM PyPI compromise. The same campaign hit four SAP CAP npm packages (@cap-js/sqlite, @cap-js/postgres, @cap-js/db-service, mbt) on April 29, 2026, and the intercom-client npm package the same week. SecurityWeek reports approximately 1,800 victims across the three package groups; OX Security tracks roughly 1,200 attacker repositories tied to the SAP CAP phase.

Socket’s analysis of the lightning artifacts confirms the same persistence module observed in the SAP CAP variant: dropped .claude/settings.json SessionStart hooks and .vscode/tasks.json runOn: folderOpen entries that re-execute the payload whenever a developer reopens the project in Claude Code or VS Code. That makes this a notable credential-stealing supply-chain campaign weaponizing AI coding agent configuration files as a persistence surface across both PyPI and npm in the same week. MITRE ATT&CK coverage: T1195.002 Compromise Software Supply Chain, T1552.001 Credentials in Files, T1546 Event Triggered Execution, T1059.006 Python.

The Authority Path That Failed

The failure starts at Lightning AI’s release pipeline. A non-human identity authorized to publish to the lightning distribution on PyPI was exercised to upload 2.6.2 and 2.6.3 — releases that the project maintainers never sanctioned. Public reporting does not yet identify the specific initial-access vector for that NHI; token theft, account takeover, or CI compromise are all consistent with current evidence. The trust anchor that failed first was the publish-credential boundary on PyPI itself: nothing prevented unauthorized releases from being indexed and served before downstream consumers, and Socket’s scanner caught both versions. Quarantine and the GitHub Security Advisory are post-hoc containment, not pre-event controls.

The second authority failure happens on every machine that imported the malicious release. Python packaging hands an installed dependency the same identity scope the importing process holds, so any GitHub PAT, cloud SDK credential, or CI secret reachable from the workstation or runner is in scope the moment lightning>=2.6.2 is loaded. The dropped .claude/settings.json and .vscode/tasks.json files extend that exposure across IDE and AI-agent sessions: the agent framework re-executes the payload at the next folderOpen or Claude Code session start, even after the malicious version is uninstalled. The gap between held scope (whatever GitHub and cloud secrets the runner carries) and exercised scope (whatever the dropped agent config will run next session) is exactly what an SV0 inventory of dependency-bearing NHIs would have surfaced before April 30.

SecurityV0 Perspective

This maps to nhi_compromise (ASI06). The end-to-end chain consumed machine identities on both sides — a maintainer-side publishing token at Lightning AI, and a fan-out across whichever CI runners and developer workstations imported the malicious version. SV0’s evidence pack would name the specific NHI authorized to publish each AI-supply-chain dependency the organization depends on (lightning, litellm, langchain, MCP servers, AI training utilities), list its rotation cadence and Trusted Publishing posture, and tie that NHI to the inventory of consumer-side service accounts authorized to import the package. The pre-exfiltration question the pack answers is which CI and developer NHIs are authorized to import lightning, and what GitHub and cloud scopes do those identities carry. The post-exfiltration question is which attacker-controlled GitHub repositories were created under our org or any developer account in the last 72 hours, and which of our cloud credentials were reachable on a host that imported lightning>=2.6.2 between 2026-04-30 09:00 UTC and the quarantine window.

The secondary angle is unproven_execution (ASI05). The dropped .claude/settings.json SessionStart hook and the .vscode/tasks.json runOn: folderOpen entry convert AI-coding-agent and IDE configuration files into an execution surface the deploying operator never approved. This is the Langflow-CSV-Agent pattern moved one layer down the stack: the unauthorized tool is no longer a framework default but a backdoored dependency that rewrites the agent’s startup contract. SV0’s authority-path framing would surface every workstation where Claude Code or VS Code can execute commands sourced from a .claude/settings.json or .vscode/tasks.json whose hash does not match the operator-approved baseline.

What To Do

  • Pin the AI-supply-chain dependency set, not just direct dependencies. Treat lightning, litellm, langchain, MCP servers, and adjacent AI-training packages as the small, high-blast-radius population they are: pin to known-good versions in lockfiles, require signed manifests for upgrades, and refuse >= ranges in CI for this set. lightning 2.6.1 is the last safe baseline.
  • Inventory .claude/settings.json and .vscode/tasks.json across every workstation and CI runner. Treat unexpected SessionStart hooks, runOn: folderOpen entries, or unfamiliar shell command strings in those files as incident indicators. Diff against a known-good baseline; alert on any creation or modification within the April 29–May 1 window.
  • Rotate every developer and CI credential reachable from a host that installed lightning>=2.6.2. GitHub PATs and fine-grained tokens, npm publish tokens, AWS/Azure/GCP SDK credentials, kubeconfigs, and Hugging Face tokens all qualify. Prefer revoke-then-reissue over rotate-in-place; the malicious code reads files at import time, not just on first run.
  • Sweep your GitHub orgs and personal accounts for newly created repositories that match the campaign signature. Any unexpected public repository created under a developer or service account between 2026-04-29 and 2026-05-01 should be triaged as potential exfiltration evidence, not noise. OX Security’s reporting tracks ~1,200 such repositories tied to the SAP CAP phase alone.
  • Adopt PyPI Trusted Publishing (OIDC) for first-party AI-adjacent packages you publish. Long-lived PyPI tokens are exactly the publishing NHI that Mini Shai-Hulud has now exploited twice in six weeks. Trusted Publishing replaces the static credential with a per-build OIDC trust to a specific GitHub repository and workflow, removing the stand-alone token from the maintainer attack surface.

Sources