Skip to content
Tech News
← Back to articles

Mini Shai-Hulud Strikes Again: 314 npm Packages Compromised

read original get npm package security kit → more articles
Why This Matters

The recent compromise of 314 npm packages highlights a significant security breach that affects millions of users and numerous popular projects. The attack demonstrates sophisticated techniques to harvest sensitive credentials and establish persistent backdoors, posing serious risks to both developers and consumers. This incident underscores the urgent need for improved supply chain security and proactive vulnerability management in the tech industry.

Key Takeaways

TL;DR

The npm account atool ( [email protected] ) was compromised on May 19, 2026. The attacker published 637 malicious versions across 317 packages in a 22-minute automated burst. Affected packages include size-sensor (4.2M downloads/month), echarts-for-react (3.8M), @antv/scale (2.2M), timeago.js (1.15M), and hundreds of @antv scoped packages. The payload is a 498KB obfuscated Bun script that matches the Mini Shai-Hulud toolkit used in the SAP compromise three weeks earlier: same scanner architecture, same credential regex set, same obfuscation pattern. It harvests credentials across the full AWS chain (env vars, config files, EC2 IMDS, ECS container metadata, Secrets Manager), Kubernetes service account tokens, HashiCorp Vault, GitHub PATs, npm tokens, SSH keys, and more. Stolen data is exfiltrated by committing it as Git objects to public GitHub repositories created under the compromised token, with the User-Agent forged as python-requests/2.31.0 . In CI environments, the payload exchanges GitHub Actions OIDC tokens for npm publish tokens, signs artifacts via Sigstore (Fulcio + Rekor) using the stolen identity, and injects persistence into .github/workflows/codeql.yml . The payload hijacks Claude Code and Codex by injecting SessionStart hooks that re-execute the malware on every AI session, both locally and via commits to accessible GitHub repositories. VS Code gets a tasks.json with "runOn": "folderOpen" for the same effect. A persistent systemd service / macOS LaunchAgent ( kitty-monitor ) installs a GitHub dead-drop C2 backdoor: a Python daemon that polls GitHub’s commit search API hourly for RSA-PSS signed commands in commit messages containing the keyword firedalazer , then downloads and executes arbitrary Python from the signed URL. A separate gh-token-monitor daemon polls stolen GitHub tokens at 60-second intervals. The payload also attempts Docker container escape via the host socket and propagates infection to other local Node.js projects.

The attack uses two execution paths. Each compromised version adds a preinstall hook ( bun run index.js ). 630 of 637 versions also inject an optionalDependencies entry pointing to imposter commits in the antvis/G2 GitHub repository. These are orphan commits with forged authorship, invisible in the repo’s branch history, exploiting GitHub’s fork object sharing to host a second copy of the payload without any write access to the target repository. npm’s github: dependency resolution fetches and executes the content by SHA.

Impact:

Projects using semver ranges (e.g., ^3.0.6 for echarts-for-react ) auto-resolve to compromised versions

for ) auto-resolve to compromised versions Credential harvesting targets npm tokens, GitHub PATs, AWS keys (full credential chain including EC2 metadata and ECS container credentials), GCP service accounts, Azure credentials, database connection strings, Stripe keys, Slack tokens, SSH keys, Docker auth, Kubernetes service account tokens, and HashiCorp Vault tokens

Exfiltrated data is committed to public GitHub repositories created under the stolen token’s account, using the GitHub API as a C2 channel disguised with a python-requests/2.31.0 User-Agent

User-Agent npm OIDC token exchange in CI allows the attacker to obtain publish tokens using the pipeline’s own identity

Sigstore signing with stolen OIDC tokens creates legitimately-signed artifacts with forged provenance

Docker socket access enables privileged container escape with host filesystem bind mounts

... continue reading