Lyrie
Supply-Chain Deep-Dive
0 sources verified·10 min read
By Lyrie.ai Senior Analyst Desk·5/3/2026

TL;DR

Between 24 April and 30 April 2026, a threat actor known as TeamPCP deployed a new campaign called "Mini Shai-Hulud" — a three-stage, cross-ecosystem supply chain worm targeting developers working in AI/ML, cloud data engineering, and enterprise SaaS. The campaign compromised at least six packages across npm and PyPI, including the PyTorch Lightning AI training framework (lightning 2.6.2/2.6.3), SAP ecosystem packages (@cap-js/sqlite, @cap-js/postgres), Intercom's client library (intercom-client 7.0.4/7.0.5), and the dbt observability CLI elementary-data (0.23.3, 1.1M monthly downloads).

The malware harvests cloud credentials from AWS, Azure, GCP, Kubernetes, GitHub, npm, and CI/CD runners — then weaponises the victim's own publishing tokens to self-replicate into new packages and repository branches, authored under an identity designed to impersonate Anthropic's Claude Code. TeamPCP has publicly named LAPSUS$ as a "good partner" in the operation. The C2 infrastructure uses a dynamic fallback mechanism anchored to a GitHub keyword (beautifulcastle) to survive takedowns.

All malicious versions have been quarantined by PyPI and npm. Immediate rotation of all secrets in affected environments is mandatory.


Background: The Shai-Hulud Lineage

TeamPCP is not new. Their Shai-Hulud and Shai-Hulud 2.0 campaigns (September–December 2025) pioneered the template: embed an obfuscated JavaScript payload inside a legitimate npm package wheel, download the Bun JavaScript runtime at runtime (avoiding static analysis detection), execute credential harvesting at import/install time, and self-propagate by poisoning the victim's own package management identity.

The name is a deliberate Dune reference — Shai-Hulud is the great sandworm, enormous, unstoppable, and territorial. Mini Shai-Hulud carries the same architecture but has been miniaturised for speed and stealth: smaller initial footprint, tighter target scope, faster kill-chain, and now operating across both npm and PyPI simultaneously — a strategic escalation that doubles the potential victim pool and bridges the gap between JavaScript and Python developer tooling ecosystems.

The campaign's timing is significant. April 2026 was marked by a surge in AI coding agent adoption (Cursor, GitHub Copilot, Gemini CLI), where developers increasingly pip install ML libraries directly from agents' suggestions without reviewing wheel contents. The choice of PyTorch Lightning — the dominant high-level PyTorch abstraction used across academic and enterprise AI training — as a vehicle suggests TeamPCP is deliberately targeting AI infrastructure builders, not just generic open-source consumers.


Technical Analysis

Stage 1: Initial Compromise Vector (Two Entry Points)

Vector A — Developer Account Compromise (PyTorch Lightning, SAP npm)

For lightning and the SAP cap-js packages, indications point to direct developer account compromise — likely through credential theft from a prior Shai-Hulud or Shai-Hulud 2.0 victim, or a targeted phishing campaign against the maintainers. The GitHub project for Lightning-AI shows anomalous commit activity in the 24 hours preceding the April 30 malicious publish. PyPI administrators quarantined lightning 2.6.2 and 2.6.3 within hours of detection by Socket's AI scanner — which flagged both versions as potentially malicious 18 minutes after publication.

Vector B — GitHub Actions Script Injection (elementary-data)

The elementary-data compromise is more surgically documented. On 24 April 2026, 22:10 UTC, a two-day-old GitHub account (realtungtungtungsahur) posted a crafted comment on PR #2147 in the elementary-data repository.

The target was update_pylon_issue.yml, a workflow that handled issue and PR comment events. Its run: block directly interpolated ${{ github.event.comment.body }} into a shell script before bash parsing — a classic GitHub Actions expression injection vector. Because the expression is evaluated at workflow-template time (not as a sanitised string argument), injecting shell metacharacters through the comment body executes arbitrary code in the runner. Critically, the attacker needed zero write access to the repository. The GITHUB_TOKEN in scope had sufficient permissions to create commits, push tags, and dispatch downstream workflows.

Using the stolen token, the attacker forged an orphan commit:

  • Hash: b1e4b1f3aad0d489ab0e9208031c67402bbb8480
  • Authored as: github-actions[bot]
  • Carried a forged "Verified" PGP signature
  • Message copied verbatim from a legitimate merged PR: release/v0.23.2 (#2188)

The orphan was tagged v0.23.3 and the repository's own release workflow was dispatched with tag=v0.23.3 as input. Because the checkout step used ref: ${{ inputs.tag || github.ref }}, the CI/CD pipeline packaged the malicious code through the legitimate pipeline. By 22:20 UTC — ten minutes after the initial comment — elementary-data==0.23.3 was live on PyPI. The injected job remained active for two hours and 46 minutes.

Stage 2: The Payload Architecture

All compromised packages share a core payload architecture confirmed by Socket, Aikido Security, Wiz, OX Security, and StepSecurity:

Hidden runtime directory — The malicious lightning wheel contains a _runtime/ directory invisible to standard pip show inspection. SAP packages use a preinstall script in package.json that triggers setup.mjs during npm install.

Bun runtime bootstrapper — The first-stage script downloads the Bun JavaScript runtime to the victim's local machine. This technique bypasses most Python/Node static analysis tools, which are not equipped to analyse Bun-executed JavaScript payloads. The Bun binary itself is clean; only the script it executes is malicious.

11MB obfuscated payload — In the lightning case, Bun executes router_runtime.js (11MB, heavily obfuscated). In SAP packages, the equivalent is execution.js. These are not simple infostealers — they are full credential harvesting and propagation frameworks containing:

  • Comprehensive regex-based secret extraction targeting:

- GitHub tokens (ghp_, ghs_, gho_)

- npm publish tokens

- AWS access keys (AKIA*)

- Azure and GCP service account credentials

- Kubernetes API server tokens (via local service endpoint enumeration)

- HashiCorp Vault configurations

- Database connection strings

- .env files and shell history

- Stripe, Slack, and Twilio API keys

- GitHub Actions runner memory (CI/CD-specific collection)

  • GitHub token validation — Harvested GitHub tokens are validated against api.github.com/user before use, confirming they are live and determining accessible repository scope.

Exfiltration infrastructure — Primary exfil domain is zero.masscan[.]cloud. A dynamic fallback mechanism retrieves updated C2 configuration by searching GitHub for commits containing the keyword "beautifulcastle", which embeds a base64-encoded payload pointing to 94.154.172[.]43/v1/telemetry. This "dead-drop" C2 pattern allows TeamPCP to update exfil endpoints without publishing new malicious package versions — surviving individual domain takedowns.

Stage 3: Worm Self-Propagation (The Distinctive Escalation)

This is where Mini Shai-Hulud earns its name. Once the malware has harvested a victim's credentials, it does not stop at exfiltration — it becomes the victim:

GitHub repository poisoning: Using validated GitHub tokens, the worm pushes malicious commits to up to 50 branches accessible by the stolen token. Every poisoned commit is authored using a hardcoded identity designed to impersonate Anthropic's Claude Code — exploiting developer trust in AI coding assistants to avoid scrutiny. The operation is an upsert: it silently overwrites files if they exist without pre-checking content, ensuring contamination even in active repositories.

npm package worm: The malware modifies the developer's local npm packages by injecting a postinstall hook into package.json, then increments the patch version and repacks the .tgz tarball. If the developer subsequently publishes the package from their local environment — a routine CI/CD action — the tampered version lands on npm, from where it propagates to downstream consumers. The setup.mjs bootstrapper is byte-for-byte identical across all observed variants, serving as a cryptographic fingerprint of Shai-Hulud ancestry.

Russian locale guardrail: A system check terminates execution if LANG or date/time locale variables begin with 'ru'. This pattern — consistent across all Shai-Hulud variants — is a standard operational security measure among Russian-aligned threat actors to avoid generating domestic victims that could attract FSB attention. It does not constitute definitive attribution but is a consistent behavioral signal.


Indicators of Compromise (IOCs)

| Type | Indicator |

|------|-----------|

| Malicious packages | lightning==2.6.2, lightning==2.6.3 |

| | elementary-data==0.23.3 |

| | [email protected], [email protected] |

| | @cap-js/sqlite (compromised versions), @cap-js/postgres (compromised versions) |

| C2 domain | zero.masscan[.]cloud |

| C2 IP | 94.154.172[.]43 |

| C2 path | /v1/telemetry |

| Dead-drop keyword | "beautifulcastle" (GitHub commit search term for dynamic C2) |

| Commit identity | Impersonates Anthropic's Claude Code (claude[bot] or similar) |

| Detection marker | $TMPDIR/.trinny-security-update (Linux/macOS) |

| | %TEMP%\.trinny-security-update (Windows) |

| Forged commit hash | b1e4b1f3aad0d489ab0e9208031c67402bbb8480 (elementary-data) |

| Malicious GA account | realtungtungtungsahur (GitHub, 2-day-old account) |

| Snyk advisory | SNYK-PYTHON-ELEMENTARYDATA-16316110 (CVSS v4.0: 9.3) |

| Bun runtime | Downloaded as first stage; presence in unexpected paths is suspicious |

| Hidden directory | _runtime/ within Python wheel (lightning) |


Lyrie Take

Mini Shai-Hulud represents the clearest signal yet that supply chain attacks are no longer blunt-instrument campaigns against generic developers. TeamPCP has made a deliberate pivot toward AI infrastructure and ML training environments:

1. Target selection is surgical. PyTorch Lightning is not chosen by accident. It is the package that data scientists at every major AI lab and enterprise ML team use to standardise training runs. Compromising it means landing on GPU clusters, model training infrastructure, and the secrets that CI/CD pipelines inject into those environments — AWS/GCP credentials with access to S3 buckets holding model weights, dataset stores, and experiment trackers.

2. The Claude Code impersonation is a trust exploit, not a technical one. Developers in 2026 are increasingly conditioned to approve and merge AI-authored commits without the same review friction applied to human commits. TeamPCP is operationalising that habit. A commit authored by "Claude Code" in a busy AI-forward repository will receive less scrutiny than an unknown committer. This is social engineering at the CI/CD layer.

3. The worm architecture makes containment non-linear. Once a developer with publish access installs a compromised package and publishes another package from the same environment, the worm has achieved second-order propagation independently of TeamPCP's infrastructure. Traditional "remove the malicious version" responses don't address packages already republished by unwitting victims.

4. LAPSUS$ co-claiming ownership matters. LAPSUS$ historically specialised in social engineering and identity theft against major tech companies. Their involvement suggests Mini Shai-Hulud may have a broader initial access component — not just opportunistic CI/CD chain riding but potentially targeted credential theft against named maintainers of high-value packages.

5. The Russian locale guardrail is a pattern, not proof. We note it as an attribution signal consistent with prior Shai-Hulud campaigns without asserting nation-state direction. TeamPCP may be a financially motivated crew with Russian-speaking members applying standard OpSec, a GRU-adjacent unit with plausible deniability, or something in between.


Defender Playbook

Immediate (if you used lightning 2.6.2/2.6.3, elementary-data 0.23.3, intercom-client 7.0.4/7.0.5, or the compromised SAP cap-js versions):

1. Rotate all secrets immediately — GitHub tokens (PAT and Actions secrets), npm publish tokens, AWS/GCP/Azure credentials, Kubernetes service account tokens, and any API keys present in ~/.env, shell history, or CI/CD environment variables on the affected machine.

2. Audit GitHub repositories accessible by those tokens for anomalous commits, new branches, or modified package.json files — particularly any commits authored by AI-sounding identities in unexpected timeframes.

3. Scan npm packages you maintain for unexpected postinstall hooks or version increments you did not make.

4. Block network access to zero.masscan[.]cloud and 94.154.172[.]43 at perimeter/DNS.

5. Revoke and regenerate PyPI tokens if any CI/CD pipeline published packages from an environment that had the malicious package installed.

Structural (prevent the next campaign):

  • Pin all dependencies to exact hashes (pip install --require-hashes / npm ci with lockfiles). Version-range installs are the primary infection vector.
  • Enable GitHub Actions security controls: set GITHUB_TOKEN permissions to minimum scope (contents: read for most workflows), use permissions: {} top-level blocks, and never interpolate ${{ github.event.comment.body }} directly into shell run steps — always pass through an intermediate environment variable (env: BODY: ${{ github.event.comment.body }} then reference $BODY).
  • Implement harden-runner (StepSecurity) or equivalent network egress monitoring for GitHub Actions runners to detect unexpected outbound calls to domains like masscan.cloud.
  • Add package.json diff review to your PR process — postinstall script additions are a red flag regardless of the change's stated purpose.
  • Treat AI-authored commits with the same scrutiny as human commits — a "Claude Code" identity in your Git log is not inherently trustworthy.
  • Monitor PyPI and npm for new versions of your critical dependencies via tools like Socket, Snyk, or Dependabot — the 18-minute detection window on lightning shows automated scanning works; make sure yours is on.

Sources

  • Socket Research Team — lightning PyPI Package Compromised in Supply Chain Attack (April 30, 2026): https://socket.dev/blog/lightning-pypi-package-compromised
  • Wiz Research — Supply Chain Campaign Targets SAP npm Packages with Credential-Stealing Malware (April 29–30, 2026): https://www.wiz.io/blog/mini-shai-hulud-supply-chain-sap-npm
  • 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
  • Snyk Research — Malicious Release of elementary-data PyPI Package Steals Cloud Credentials from Data Engineers (April 26, 2026): https://snyk.io/blog/malicious-release-of-elementary-data-pypi-package-steals-cloud-credentials-from-data-engineers/
  • StepSecurity — A Mini Shai-Hulud Has Appeared: Obfuscated Bun Runtime Payloads Hit SAP-Related npm Packages: https://www.stepsecurity.io/blog/a-mini-shai-hulud-has-appeared
  • Semgrep — Shai-Hulud Themed Malware Found in the PyTorch Lightning AI Training Library: https://semgrep.dev/blog/2026/malicious-dependency-in-pytorch-lightning-used-for-ai-training/
  • Dark Reading — TeamPCP Hits SAP Packages With 'Mini Shai-Hulud' Attack (May 2, 2026): https://www.darkreading.com/cloud-security/teampcp-sap-packages-mini-shai-hulud
  • Snyk Advisory — SNYK-PYTHON-ELEMENTARYDATA-16316110 (CVSS v4.0: 9.3)
  • Lightning-AI GitHub Security Advisory — GHSA-w37p-236h-pfx3

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.