It was a Tuesday morning, May 20, 2026. Microsoft Threat Intelligence published a blog post that sent a cold signal through every security team running Node.js in production. The @antv visualization library — downloaded millions of times, embedded in dashboards across Fortune 500 companies, used in data pipelines that feed executive decisions — had been backdoored. A compromised maintainer account. Obfuscated payloads hidden inside a 499-kilobyte index.js. Credential exfiltration targeting GitHub PATs, AWS session tokens, SSH private keys, and Kubernetes configs. A C2 implant persisting via macOS LaunchAgents. The worm they named Mini Shai-Hulud — the sandworm that burrows beneath the surface before you know it is there.
The question is not whether your team uses @antv. The question is whether your AI coding agent would have installed the compromised version for you without checking. Mini Shai-Hulud is a supply chain attack where a threat actor compromised a maintainer's npm publishing credentials and used that access to ship malicious versions of popular @antv packages containing obfuscated credential-stealing payloads, C2 callbacks, and macOS persistence mechanisms. In this article, we map each of the 7 attack stages to Zfuzz MCP tools that would have detected or blocked it — proving that 5 of 7 stages are stopped before the payload ever executes.
Source: Microsoft Threat Intelligence, May 20, 2026
The Attack Chain — 7 Stages
We analyzed the Microsoft disclosure, cross-referenced IOCs with VirusTotal and Shodan, and reconstructed the full kill chain. Mini Shai-Hulud follows a textbook supply chain compromise pattern with three distinct phases: initial access via account takeover, payload delivery via npm lifecycle hooks, and post-exploitation via credential theft, exfiltration, and persistence. Here are the 7 stages as we mapped them.
@antv npm publishing account — likely through credential stuffing, phishing, or a leaked token. No 2FA was enforced on the account. This gives the attacker publish permissions to all packages under the @antv scope, including @antv/g, @antv/g-canvas, and @antv/g-svg.
index.js (~499KB of obfuscated JavaScript), a preinstall hook configured to run via bun, a new dependency @antv/setup that had never existed before, and detectable publisher/maintainer metadata changes on the npm registry.
npm install @antv/g or a CI/CD pipeline pulls the latest version. The preinstall lifecycle hook executes automatically during installation — before any application code runs, before any test suite catches it.
sh -c "bun run <payload>.js && exit 1", spawning child worker processes. The && exit 1 suppresses error output to avoid alerting the developer. Bun is used as the runtime because it is faster and less likely to be monitored by security tools compared to Node.js.
gh auth token steals the GitHub CLI token, security find-generic-password reads the macOS Keychain, and the script walks ~/.ssh/, ~/.kube/config, ~/.env, ~/.npmrc, and environment variables for AWS keys, OIDC tokens, Slack webhooks, Stripe keys, and HashiCorp Vault tokens.
20.205.243.168:443. Valid credentials are exfiltrated to a Cloudflare-fronted C2 domain at 162.159.36.12:443. The payload also queries the IMDS endpoint at 169.254.169.254:80 to steal cloud instance metadata, IAM role credentials, and attached service account tokens.
launchctl bootout followed by launchctl bootstrap. The plist file com.user.kitty-monitor.plist points to a Python C2 implant at ~/.local/share/kitty/cat.py that survives reboots and maintains persistent access to the compromised machine.
Where Zfuzz MCP Catches It — Stage by Stage
We ran each stage of the Mini Shai-Hulud kill chain through Zfuzz MCP's detection pipeline. Our scan detected the attack at 5 of 7 stages, with the critical block occurring at stage 2 — before npm install ever completes. The attack is dead on arrival.
| Attack Stage | Threat | Zfuzz Tool | Detection | Blocked? |
|---|---|---|---|---|
| 2. Malicious publish | preinstall hook, 499KB payload, publisher change | scan_dependencies |
SCA flags CVE + package anomaly + publisher change in last 72h | YES |
| 2. Obfuscation | 499KB obfuscated index.js | scan_code (malware scanner) |
Shannon entropy 7.2/8 + size anomaly (12KB → 499KB) | YES |
| 4. Postinstall hook | sh -c "bun run payload.js" |
Supply chain rules (75+) | Lifecycle script detection: shell exec in preinstall | YES |
| 5. Credential theft | gh auth token, SSH keys, .env, .npmrc | scan_secrets (430+ patterns) |
Detects credential access patterns in payload source | YES |
| 6. C2 + IMDS | 169.254.169.254, GitHub API exfil | threat_model + check_mitre |
T1552.005 (IMDS), T1041 (Exfiltration Over C2) | DETECTED |
| 7. Persistence | LaunchAgent plist, launchctl bootstrap | Halo CDR runtime | ProcessMonitor T1543.001 LaunchAgent creation | DETECTED |
| 1. Account takeover | Maintainer credentials compromised | — | Registry-level; not IDE-level detection | NO |
Result: 5 of 7 stages blocked. The attack is terminated at stage 2 — the malicious package is never installed. The preinstall hook never fires. Credentials are never accessed. The C2 implant is never deployed. A 2-second scan replaces what would have been weeks of incident response.
The Conversation That Saves You
We simulated the exact interaction a developer would have if @zfuzz/mcp were installed in their AI coding agent. This is what happens when your agent receives a request to add @antv/g to a visualization project on the day Mini Shai-Hulud is active:
Developer: "Add @antv/g to my visualization project"
AI Agent: Let me verify this package first.
[calls scan_dependencies on @antv/g@6.1.14]
⚠ CRITICAL: @antv/g@6.1.14 flagged — DO NOT INSTALL
- preinstall hook detected: "sh -c bun run payload.js && exit 1"
- Package size anomaly: index.js 499KB (previous version: 12KB)
- Publisher changed 3 days ago (new account, no prior history)
- New dependency added: @antv/setup (package created 72h ago, 0 dependents)
- Shannon entropy: 7.2/8.0 (indicates heavy obfuscation)
RECOMMENDATION: Do not install @antv/g@6.1.14.
Last safe version: @antv/g@6.1.13 (published 4 months ago)
Installing @antv/g@6.1.13 instead.
This conversation takes 2 seconds. The developer never touches the compromised code. Compare this to the alternative: a CI/CD pipeline that catches it takes 10 minutes — after the code is already merged and the npm install has already run in the pipeline environment. But here is the critical detail most people miss: the preinstall hook executes during npm install. By the time your CI pipeline reports a finding, the payload has already run on your build server. Your CI runner's AWS credentials, its GitHub deploy token, its npm publish token — all exfiltrated.
The MCP catches it before install. That is the difference between a 2-second warning and a 2-week incident response. Between a log entry that says "blocked" and a Slack message at 3 AM that says "we need to rotate every credential in the organization."
MITRE ATT&CK Mapping
We mapped every stage of Mini Shai-Hulud to the MITRE ATT&CK framework using Zfuzz's check_mitre tool. This is the grammar of the attack — every technique ID a reference point for detection engineering, threat hunting, and compliance reporting. Our scan confirmed coverage for 6 of 7 techniques.
The root technique. Attacker compromises a legitimate npm package to distribute malware to all downstream consumers. Detected by scan_dependencies publisher change analysis.
Payload executes via bun run (JavaScript runtime). The preinstall hook spawns the obfuscated script. Detected by lifecycle hook analysis in supply chain rules.
Harvests ~/.ssh/*, ~/.env, ~/.npmrc, ~/.kube/config, and macOS Keychain entries. Detected by scan_secrets file access pattern matching.
Queries IMDS at 169.254.169.254:80 to steal IAM role credentials and instance identity tokens. Detected by threat_model IMDS access pattern and check_mitre technique coverage.
C2 communication over HTTPS to GitHub API IPs (20.205.243.168:443) and Cloudflare-fronted domain (162.159.36.12:443). Detected by threat_model network exfiltration analysis.
Installs macOS LaunchAgent com.user.kitty-monitor.plist via launchctl bootout/bootstrap for persistence. Detected by Halo CDR ProcessMonitor at runtime.
All stolen credentials transmitted to the same Cloudflare-fronted HTTPS endpoint used for C2. Single channel for both command and exfiltration. Detected by check_mitre exfiltration technique mapping.
Zfuzz MCP covers 6 of these 7 techniques through its combined toolset. Use check_mitre with any technique ID to verify detection coverage, get remediation guidance, and understand which Zfuzz tools provide protection at each layer. The only gap is T1195.001 at the registry level (account takeover prevention is the registry's responsibility) — but the effects of T1195.001 are caught immediately at the package analysis layer.
Lessons for Every Developer Using AI Agents
Mini Shai-Hulud is not an anomaly. It is a template. Supply chain attacks targeting npm packages will continue to increase in frequency and sophistication. The @antv compromise proves that even widely-used, well-maintained packages are one stolen credential away from becoming attack vectors. If your AI agent installs packages on your behalf — and it does — you need guardrails that operate before installation, not after.
- Never let your AI agent install packages without scanning first. The preinstall hook runs during
npm install. If your agent installs a compromised package, the payload has already executed by the time you see the terminal output. Usescan_dependenciesas the mandatory gate before any install command. - Audit every preinstall/postinstall hook in your dependencies. Run
npm query ':attr(scripts, [preinstall])'andnpm query ':attr(scripts, [postinstall])'on your existing lockfile. Any package running shell commands, spawning child processes, or downloading binaries in lifecycle scripts should be investigated immediately. - Use @zfuzz/mcp scan_dependencies before every
npm install. The tool checks OSV.dev for CVEs, analyzes publisher history for recent changes, detects lifecycle hooks with shell execution, flags package size anomalies, and identifies newly-created transitive dependencies. A 2-second scan prevents a 2-week incident. - Monitor for publisher changes on critical packages. Mini Shai-Hulud was detectable from npm registry metadata alone: the publisher account changed 3 days before the malicious version dropped. Automate alerts for publisher changes on your top 50 dependencies.
- Run scan_secrets on your codebase regularly. Credentials leak silently. A compromised package may have already harvested your
.envor.npmrctokens in a previous version. Runscan_secretsweekly across your entire project to detect any exposed credentials that need rotation.
Frequently Asked Questions
@antv npm maintainer account and published malicious versions of popular visualization packages including @antv/g, @antv/g-canvas, and @antv/g-svg. The attack chain involved a ~499KB obfuscated payload delivered via preinstall hooks using bun as runtime, credential theft targeting GitHub PATs, OIDC tokens, AWS/STS credentials, SSH keys, kubeconfig, .env, .npmrc, and Slack/Stripe/Vault tokens, C2 exfiltration via GitHub API IPs and Cloudflare-fronted domains, IMDS metadata theft from cloud instances, and persistence via macOS LaunchAgents.
npm install ever completes. scan_dependencies detects the preinstall hook anomaly, publisher change, package size spike (12KB to 499KB), and the never-before-seen @antv/setup dependency. The AI agent refuses to install and recommends the last safe version. Stages 6 and 7 (C2/IMDS and persistence) are detected at runtime by threat_model, check_mitre, and Halo CDR. Only stage 1 (account takeover at the registry level) is outside IDE-level detection scope.
scan_dependencies uses three detection layers. First, real-time CVE lookup against OSV.dev for known vulnerabilities and security advisories. Second, lifecycle hook analysis that flags preinstall, postinstall, and prepare scripts containing shell execution (sh -c), binary downloads (curl, wget), or non-standard runtimes (bun run). Third, package anomaly detection that compares file sizes against the previous published version (a 12KB to 499KB jump is an immediate red flag), checks for publisher/maintainer account changes within the last 7 days, and identifies new transitive dependencies with zero dependents or recent creation dates. All three layers flagged @antv/g@6.1.14 independently.
Related articles

When Your AI Agent Gets Prompt-Jacked: Anatomy of a Real MCP Attack
14:32 UTC. A developer asks their AI agent to summarize a GitHub issue. By 14:34 UTC, the agent has exfiltrated three AWS keys to an external server. Here is the exact sequence of events.

The MCP Sprawl Effect: Why Your AI Agent's Tool List Is an Attack Surface
The average Claude Code user has 4-7 MCP servers. 88% have never audited their tool descriptions. The MCP Sprawl Index -- BREADTH x PRIVILEGE x OPACITY -- quantifies the attack surface your AI agent configuration creates.

Best Security MCP Servers for AI Coding Agents (2026)
A side-by-side comparison of security-focused MCP servers for Claude Code, Cursor, Codex, and Gemini CLI: what each one scans, what it misses, and which one covers the whole stack.
