Shai-Hulud copycat campaign targets Python developers through PyPI typosquatting (opens in new tab)
GitLab researchers uncovered a coordinated PyPI supply-chain campaign distributing a copy of the Shai-Hulud worm. Five packages—four typosquats and one compromised legitimate project—execute malware during Python startup, steal credentials from CI/CD and cloud environments, and propagate through developers’ repositories and package registries. The campaign demonstrates that Python packages can be weaponized without imports or explicit function calls.
Malicious PyPI Packages
- All packages were published by the
elitexpaccount:rlaskandtlask, typosquats of Flaskrsquests, a typosquat of Requestsnhmpy, a typosquat of NumPymflux-streamlit, a legitimate project later weaponized in versions0.0.3and0.0.4
- The attacker first uploaded clean probe versions matching current upstream version numbers, then replaced them with payload-bearing releases.
- The activity followed the public release of Shai-Hulud’s source code, suggesting an independent copycat operation targeting Python users.
Python Startup-Based Infection
- The malware uses Python
.pthfiles, which Python processes automatically at startup. - The dropper:
- Checks for a
.bun_ranmarker in the temporary directory. - Downloads the Bun JavaScript runtime from GitHub.
- Executes a roughly 5 MB obfuscated JavaScript payload.
- Checks for a
- Early
rlaskversions also includedsitecustomize.py, which searchedsys.pathfor and executed a hidden_index.jsfile. - This approach requires no explicit package import or function invocation.
Payload Obfuscation
- The JavaScript is protected by multiple layers:
- Package-specific ROT-N encoding
- AES-128-GCM encryption
- Variable-name mangling using
_0xidentifiers
- Researchers identified:
- A small encrypted Bun downloader
- A 772 KB Shai-Hulud credential stealer
- Approximately 2,538 hardcoded strings
Credential Theft
The worm targets credentials and secrets from:
- GitHub Actions tokens, repository secrets, OIDC tokens, artifacts, and runner memory
- AWS IAM credentials, instance metadata, Secrets Manager, SSM, and STS tokens
- Azure managed identities, Key Vault, and Microsoft Graph tokens
- GCP service-account keys and application credentials
- HashiCorp Vault tokens and Kubernetes authentication
- npm, JFrog, PyPI, and RubyGems publishing credentials
- SSH private keys and Kubernetes service-account tokens
- Sigstore credentials and Fulcio signing certificates
- MongoDB, MySQL, PostgreSQL, and Redis connection strings
Self-Propagation
Using stolen credentials, the worm can:
- Add
.github/setup.jsand workflow files to repositories so it runs in other CI pipelines. - Insert
.github/copilot-instructions.mdto influence AI coding assistants. - Publish poisoned packages to PyPI, npm, and RubyGems.
- Attempt privilege escalation on self-hosted runners through
sudoersmodifications. - Detect StepSecurity’s harden-runner and alter its behavior.
Attacker Infrastructure and Weaponized Project
- The PyPI account was created in 2024 and was associated with the legitimate
mflux-streamlitproject. - Package uploads used
Bun/1.3.14, matching the runtime downloaded by the malware. - Unlike a pure typosquatting campaign, the compromise of a real project could affect existing users through normal dependency updates.
Developers should audit environments for the affected packages, review CI/CD and cloud credentials, rotate exposed secrets, and enforce dependency pinning and package provenance checks. CI runners and publishing tokens should be treated as potentially compromised if any affected version was installed.