Shai-Hulud Strikes Again: 19 Science PyPI Packages Trojanized to Steal Developer Secrets

The Shai-Hulud supply-chain campaign is back, and this time it’s targeting the scientific Python ecosystem. Attackers compromised 19 packages on PyPI — collectively downloaded hundreds of thousands of times — injecting malware that rifles through developer workstations for secrets and credentials.

App security firm Socket discovered the campaign, which spans 37 malicious releases attributed to what appears to be a single threat actor. Many of the infected packages are popular bioinformatics tools: Dynamo, Spateo, CoolBox, U-FISH, and Napari-UFISH. If you work in computational biology or data science and pulled any of these recently, you need to check your environment.

How the Infection Works

The attack is clever in its simplicity. Each compromised wheel ships two malicious artifacts: a *-setup.pth file and an obfuscated JavaScript payload named _index.js.

The .pth file is a Python startup hook — Python processes every .pth file in site-packages on startup, no import required. When you next run python, pip, a test suite, a Jupyter notebook, a CI job, or literally any Python command, the malicious .pth fires. It downloads the Bun JavaScript runtime from GitHub and uses it to execute the bundled script.

That means the infection is delayed. You install the package today and nothing happens. Tomorrow, when your CI pipeline spins up or you restart your notebook kernel, the payload fires on the next Python invocation. By then, you’ve moved on and the connection to the original install is easy to miss.

What Gets Stolen

The JavaScript stealer casts an absurdly wide net. It targets:

Publishing tokens: GitHub, npm, PyPI, RubyGems, JFrog
Cloud credentials: AWS, GCP, Azure, Kubernetes, Vault
Git and infrastructure: SSH keys, Docker credentials
Config files: .env, .npmrc, .pypirc, shell histories
AI tool configs: Claude/MCP configuration files

That last category is notable. Claude and MCP configs can contain API keys and access tokens for AI-assisted development toolchains — exactly the kind of credentials a developer workstation holds. This attacker isn’t after your infrastructure alone; they’re after your entire development workflow.

Exfiltration and Evasion

Stolen data gets sent to automatically created GitHub repositories via GitHub Actions — the same method previous Shai-Hulud campaigns used. A second exfiltration channel uses direct HTTPS to a legitimate but invalid endpoint at api.anthropic.com/v1/api, likely chosen as camouflage to blend in with normal tool traffic.

The malware also checks for Russian locales and environments before executing — a common targeting filter among certain threat actor groups. It also looks for security tools like StepSecurity Harden-Runner and adjusts behavior to avoid detection.

Persistence is established through systemd services on Linux and LaunchAgents on macOS, and the malware also plants itself into GitHub workflow files and Claude/MCP configs to survive environment rebuilds.

The Bigger Picture

Socket is tracking this as part of the broader Shai-Hulud campaign. With this wave, the count of attributed malicious artifacts reaches 453 items. The campaign has evolved from its initial npm-focused waves into a cross-package-manager operation hitting both npm and PyPI — now with a clear focus on developer toolchains and supply chains.

The strategy is self-reinforcing: steal publishing tokens, push malicious updates to more packages, steal more tokens, repeat. Each wave expands the attack surface.

What You Should Do

If you’ve installed any of the affected packages — check Socket’s report for the full list of compromised versions — treat every secret on that machine as rotated immediately. GitHub tokens, cloud credentials, SSH keys, API tokens, everything.

Look for Python packages containing executable .pth startup hooks, unexpected downloads of the Bun runtime, and process chains where Python spawns Bun to run _index.js. Scan your CI/CD environments too — they’re a prime target since they hold the same credentials at scale.

And this is a good moment to audit your dependency hygiene. Pin your versions. Verify checksums. Treat every pip install as a code execution event, because campaigns like this one prove it literally is.