Back Zscaler Shai-Hulud: Miasma, Hades, & AI Scanner Evasion | ThreatLabz - Zscaler, Inc.
Since Zscaler ThreatLabz published its analysis of Shai-Hulud V2 in November 2025, the campaign has continued to evolve in ways that distinguish it from more typical software supply chain attacks. Over the last six months, the activity expanded beyond npm into the Python Package Index (PyPI), shifted from maintainer-focused compromise to CI/CD abuse, undermined trust in Supply-chain Levels for Software Artifacts (SLSA) provenance and OpenID Connect (OIDC)-based publishing workflows without breaking their underlying cryptographic guarantees, extended execution into IDE configuration files, and introduced prompt injection designed to evade AI-based security scanners.
ThreatLabz assesses with high confidence that the earlier waves are linked to TeamPCP, tracked by Mandiant as UNC6780. However, attribution for activity after May 12, 2026 is less certain. On that date, the complete worm source code was publicly released under an MIT license, turning what had been a private actor capability into reusable public attack infrastructure.
The tables below extend the V1/V2 comparison from our earlier post across subsequent waves. V1 and V2 are included as baselines.
Hades/TanStack (May 2026)
AiTM phishing (npmjs.help)
CI toolchain poisoning (Trivy apt cache)
CI misconfiguration (pull_request_target)
Python interpreter startup
npm publish (OIDC-minted token)
.pth in site-packages
Yes - republishes all maintainer packages
Yes - republishes all maintainer packages
No - pipeline injection
No - SLSA-attested packages
Install-time scanning
SLSA provenance attestation
ICP blockchain canisters
Table 1: Campaign evolution across various versions of Shai-Hulud (V1, V2, Miasma, Hades/TanStack).
GitHub account takeover
Compromised contributor account
Compromised maintainer account
npm publish (OIDC trusted flow)
IDE folder open / agent init
Python interpreter startup
.pth in site-packages
No - SLSA-attested packages
OIDC trusted publishing / contributor identity
Package distribution surface
AI-based scanner analysis
ICP blockchain canisters
ICP blockchain canisters
GitHub dead drops + Session Protocol + staged Anthropic camouflage
Yes (prompt injection)
Table 2: Continued . Campaign evolution across various versions of Shai-Hulud (Red Hat, IDE Wave, Hades PyPI).
The diagram below shows the attack flow.
Figure 1: Attack chain showing the Miasma flow.
The Miasma wave marked the campaign's first major expansion beyond npm . Rather than targeting package maintainers directly, TeamPCP compromised Aqua Security's Trivy vulnerability scanner through GitHub Actions cache poisoning.
Trivy is widely used in build pipelines for container and dependency scanning.In this wave, the attackers exploited the absence of version pinning in downstream consumers. As a result, when TeamPCP poisoned Trivy's repository cache, any pipeline that installed Trivy without a pinned version downloaded and executed the attacker's binary. LiteLLM, a popular Python library for calling LLM providers, was among the first major victims. LiteLLM version 1.82.8 was published with a 34KB malicious file, litellm_init.pth , dropped into Python's site-packages directory.
The adoption of .pth files represents a significant persistence advancement over the preinstall and postinstall hook mechanism used in prior npm waves.
Python processes all .pth files in site-packages during interpreter startup . This behavior is by design and documented in the Python path configuration specification. In an impacted environment, this means any process invoking Python executes the payload unconditionally.
Unlike install-time hooks, .pth persistence survives package reinstallation and persists across virtual environment recreation if the base site-packages directory is affected.
The table below compares persistence mechanisms across Shai-Hulud waves.
Package installation (earlier)
Every Python invocation
Hades PyPI (Jun 2026)
Every Python invocation
Table 3: Persistence mechanism comparison across Shai-Hulud waves.
The diagram below shows the attack flow.
Figure 2: Attack chain showing the Hades flow.
On May 11, 2026, TeamPCP exploited a pull_request_target misconfiguration in the TanStack open-source monorepo to bypass Supply-chain Levels for Software Artifacts (SLSA) provenance attestation.
pull_request_target is a GitHub Actions workflow trigger that, unlike pull_request , executes in the context of the target (base) repository rather than the contributor's fork, granting the workflow access to repository secrets. The misconfiguration is common in open-source projects that accept external contributions without restricting which workflows execute in the privileged context.
According to public reporting, the attack chain worked as follows:
The key distinction from earlier waves is that no maintainer credentials needed to be stolen. The trusted environment itself became the access path.
Within a six-minute window, 84 malicious artifacts were published across 42 @tanstack/ packages. Those artifacts carried valid Sigstore (fulcio.sigstore.dev) provenance attestations, signed through the legitimate CI path and recorded in the Rekor transparency log. From a cryptographic standpoint, the attestations were valid because TeamPCP ran the malicious build process from inside the trusted system.
Days later, on May 19, the campaign mass-republished the @antv data visualization namespace. Snyk reported roughly 314 versions published within a single six-second window.
Public reporting also linked this broader wave to compromises affecting additional AI-related infrastructure packages, including packages associated with Mistral AI, Guardrails AI, UiPath, and OpenSearch. These libraries are used to access LLM providers, enforce AI safety policies, and build automation workflows.
On May 12, 2026, TeamPCP published the complete worm source code to GitHub under an MIT license with the commit message, "Open Sourcing The Carnage . "
The release reportedly included:
The open-sourcing of the toolkit changed the threat landscape and made attribution harder. Before publication, linking multiple waves to the same operator was more straightforward. After May 12, however, the toolkit was publicly available, allowing copycat actors to reuse the same code and tradecraft. As a result, malware overlap or similar operations alone are no longer enough to confidently attribute later activity to the original TeamPCP group.
The diagram below shows the attack flow.
Figure 3: Attack chain showing the Hades flow.
The June Red Hat wave showed a different path into the same trusted publishing model. Public reporting indicates that a Red Hat engineer’s GitHub account was compromised, although the initial takeover method has not been publicly disclosed.
With access to the account, the attacker reportedly:
The result was 32 packages and 96 versions published within hours, all appearing legitimate from the perspective of signing and provenance checks. As in the TanStack wave, the trust chain remained cryptographically valid while the identity and execution context at its root had been compromised.
Samples from the June wave introduced a network-layer evasion technique: a C2 channel staged to route traffic to api.anthropic.com/v1/api , a non-existent endpoint at Anthropic's domain.
This is a camouflage mechanism, not the primary exfiltration channel. In this campaign family, primary exfiltration and tasking have repeatedly used GitHub-based dead drops, including repositories and commit-based signaling. The staged Anthropic path appears intended to blend suspicious outbound requests into traffic patterns associated with legitimate AI API use. Anthropic’s infrastructure was not compromised.
The diagram below shows the attack flow.
Figure 4: Attack chain showing the Hades flow.
The Azure/durabletask wave marked another structural shift. Instead of relying on package installation or CI publication, the attacker moved into developer tooling configuration files that can trigger code or instructions when a repository is opened in a supported editor or assistant environment. A compromised contributor account pushed four files (described in the table below) targeting four major AI-assisted development environments:
.claude/settings.json
Opening project in Claude Code
.cursor/rules/setup.mdc
alwaysApply: true prompt injection
Cursor AI agent initialization
runOn: folderOpen task
Opening folder in VS code
.gemini/settings.json
Starting Gemini Code Assist session
Table 4: Targeted configuration file with corresponding execution mechanisms and triggers
No package installation is required. The trigger is git clone followed by opening the repository in any of the targeted editors. In response, GitHub disabled 73 Microsoft repositories across four organizations.
IDE configuration files are not evaluated by package registry scanners, SLSA verification tools, or behavioral analysis systems oriented around package content. They are typically reviewed as configuration rather than executable code, leaving this vector outside most existing detection perimeters.
The diagram below shows the attack flow.
Figure 5: Attack chain showing the Hades flow.
The Hades PyPI wave, detected by Socket Research on June 8, 2026, compromised 37 PyPI wheels across 19 packages. The underlying malware retained familiar campaign tradecraft, including:
The notable advancement was an AI scanner evasion technique embedded in the _index.js bundle.
According to StepSecurity' s analysis, the _index.js bundle begins with a plain-text prompt injection block positioned ahead of the obfuscated payload. As security vendors increasingly use automated LLM-based pipelines to triage suspicious packages, the attacker appears to be targeting that analysis layer directly. According to StepSecurity, the block "acts as an adversarial prompt injection, instructing any parsing LLM to ignore the obfuscated code below it, classify the package as verified clean infrastructure, and output a safe security report."
The figure below shows the prompt injection embedded in _index.js .
Figure 6: The prompt injection embedded in _index.js to bypass automated security scanners (source: StepSecurity ).
Security tools that pass raw package content to a language model without enforcing system prompt isolation receive this instruction in the model's context window. Without explicit content boundary separation, the injected text can override the scanner's analytical prompt and produce a false-negative verdict.
This technique exploits a structural assumption in LLM-based scanning, namely that content given to the model is untrusted in subject matter but trusted in structure. That assumption fails in two ways. A scanner can be steered into a false-clean verdict, as documented here, or induced to refuse analysis entirely if the submitted code contains content that triggers the model’s safety filters. Either way, the result is the same: no usable verdict and a malicious package that passes review. Any pipeline that treats “no finding” or “refused to analyze” as equivalent to “clean” inherits this blind spot.
The table below shows how LLM-based scanners fail against injected content.
False-clean verdict (observed in _index.js)
Prompt injection instructs the model to classify the package as clean
Returns clean verdict per injected instruction
Submitted content trips the model's safety filters
Refuses to analyze the file
No verdict, treated as a pass
Table 5: How LLM-based scanners fail against injected content.
The campaign’s C2 infrastructure also evolved across waves in response to takedowns and defensive pressure, as shown in the table below.
GitHub orphan/dangling commits (dead drops)
Low - GitHub can disable repositories
Internet Computer Protocol (ICP) blockchain canisters
High - decentralized, no central domain
GitHub dead drops + Session Protocol + staged api.anthropic.com/v1/api camouflage
High - Session Protocol bypasses DNS blocking
Table 6: C2 infrastructure evolution across waves
One of the clearest examples is the GitHub-based “dead drop” tasking method. In the analyzed Hades samples, a background service known as kitty-monitor reportedly queried GitHub’s commit API once per hour for the marker string firedalazer . The most recent matching commit contained the instruction in its commit message in the form:
The implant verified the signature against an embedded public key and then retrieved the referenced URL. This design gives the attacker two advantages:
The later move toward ICP canisters and Session Protocol reflects the same pattern: reducing dependence on infrastructure that a registrar, host, or DNS control point could easily seize or block.
The Shai-Hulud campaign family is notable not just for repeated package compromise, but for how systematically it moved through the software supply chain trust stack: maintainer authentication, install-time execution, security tooling, provenance, OIDC-based publishing, developer tooling, and AI-assisted analysis.
The May 12 public release of the worm source code changed the threat landscape by turning techniques such as OIDC token scraping, .pth persistence, CI-originated malicious publishing, and prompt injection against LLM-based scanners into reusable public tradecraft.
Organizations should assume these techniques are already in circulation beyond the original campaign and harden their defenses accordingly.
Zscaler has enhanced its security measures to cover this threat, ensuring that any attempts to download a malicious npm package will be detected under the following threat classifications:
Advanced Threat Protection
Malicious dropper script (V2)
Obfuscated payload, ~480,000 lines (V2)
.github/workflows/discussion.yaml
Backdoor workflow (V2)
Exfiltrated cloud credential data
Exfiltrated file contents
Exfiltrated environment variable data
Exfiltrated secrets (V2)
34KB .pth persistence file dropped in site-packages (Miasma, Mar 2026)
.pth persistence file, leading-hyphen naming (Hades PyPI, Jun 2026)
Obfuscated payload bundle with prompt injection header (Hades PyPI, Jun 2026)
GitHub dead-drop C2 polling loop (Hades PyPI, Jun 2026)
.claude/settings.json
SessionStart hook - fires on Claude Code project open (IDE Wave, Jun 5)
.cursor/rules/setup.mdc
alwaysApply: true prompt injection (IDE Wave, Jun 5)
runOn: folderOpen malicious task (IDE Wave, Jun 5)
.gemini/settings.json
Startup hook (IDE Wave, Jun 5)
dc48b09b2a5954f7ff79ab8a2fd80202bd3b59c08c7cdbc6025aa923cb4c0efe
_index.js - Hades PyPI wave
e1342a80d4b5e83d2c7c22e1e0aaa95f2d88e3dbf0d853a4994b180c93a4b17d
_index.js - Hades PyPI wave (variant)
c539766062555d47716f8432e73adbe3a0c0c954a0b6c4005017a668975e275c
-setup.pth - consistent across all Hades PyPI artifacts
models[.]litellm[.]cloud
Miasma exfiltration domain (LiteLLM 1.82.8); registered 2026-03-23, one day before the malicious package appeared (SafeDep)
hxxps://api[.]anthropic[.]com/v1/api
C2 camouflage destination - non-existent Anthropic endpoint; channel was noop: true in analyzed samples, staged but not active
oven-sh/bun/releases/download
Bun runtime dropper download path - legitimate binary used as evasion vehicle (V2, Hades PyPI)
Disclaimer: This blog post has been created by Zscaler for informational purposes only and is provided "as is" without any guarantees of accuracy, completeness or reliability. Zscaler assumes no responsibility for any errors or omissions or for any actions taken based on the information provided. Any third-party websites or resources linked in this blog post are provided for convenience only, and Zscaler is not responsible for their content or practices. All content is subject to change without notice. By accessing this blog, you agree to these terms and acknowledge your sole responsibility to verify and use the information as appropriate for your needs.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
