A massive and highly coordinated supply chain assault is currently ripping through the JavaScript developer ecosystem. Security researchers at StepSecurity have uncovered a devastating new wave of the Mini Shai-Hulud npm worm. This time, the threat actors have successfully hijacked a high-profile npm account to poison a massive array of data visualization, charting, and mapping libraries widely used across enterprise environments.
The compromised npm account, known as atool, is the primary publisher of timeago.js (which boasts over 1.5 million weekly downloads) and holds extensive maintenance rights across Alibaba’s open-source AntV data visualization ecosystem. By hijacking this single pipeline, the attacker has systematically pushed malicious updates spanning charting (@antv/g2), graph visualization (@antv/g6), mapping (@antv/l7), and several standalone React and utility libraries.
StepSecurity has issued a warning to the global developer community: “This attack represents one of the largest coordinated npm supply chain campaigns ever documented. If you installed any affected package, assume all secrets accessible in that environment are compromised. Rotate all credentials immediately.”
The attack unfolded in a rapid, highly calculated sequence on May 19, 2026 (UTC), utilizing a distinct “double-tap” publication strategy designed to maximize delivery success across diverse build environments:
- Wave 1 (01:56 UTC): The threat actor published the initial malicious version of each targeted package. The package injected a preinstall script executing a payload via the Bun runtime (bun run index.js). If Bun wasn’t natively installed on the victim’s system, the payload would quietly download and install it in the background via a piped curl command.
- Wave 2 (02:06 UTC): Exactly ten minutes later, a second set of malicious versions rolled out. This update added bun directly as an explicit npm dependency. This ensured the payload would execute reliably even if the runtime’s dynamic web installation failed silently during Wave 1.
StepSecurity identified two distinct structural methods used to smuggle the malware into dependency trees, allowing the worm to evade traditional supply chain defenses:
Pattern A: Direct Install Hooks
The most straightforward method adds a preinstall or postinstall script directly inside the package’s published package.json file, spawning a node child process to execute the malicious index.js file. This pattern was heavily deployed across the core @antv/* namespace.
Pattern B: The Poisoned Git Commit (Optional Dependencies)
In more sophisticated instances—such as within the echarts-for-react package—the attackers utilized an incredibly stealthy mechanism. Instead of inserting a glaring malicious script directly into the published tarball, they added a field to optionalDependencies pointing directly to a compromised commit within the legitimate and trusted antvis/G2 GitHub repository:
When npm attempts to resolve this git dependency, it automatically fires a prepare hook embedded in the malicious commit’s package.json. The script concludes with an intentional && exit 1. This clever trick forces the optional dependency to gracefully fail and exit. Because it is marked “optional,” npm continues the primary installation normally, leaving minimal traces in build logs while the malware seamlessly runs in the background. Furthermore, because the source resolves to a trusted GitHub organization and contains no scripts entry in the root package, it completely evades standard static analysis tools.
The deobfuscated payload reveals a terrifyingly thorough data-harvesting machine. Packaged as a massive 486 to 498 KB JavaScript file protected by a heavily layered, PBKDF2-seeded Fisher-Yates obfuscation scheme, the worm’s capabilities target maximum privilege extraction.
The worm’s most severe capability is engineered to target GitHub Actions runners directly. It hunts down the Runner.Worker process by scanning the system’s command-line structures (/proc/[pid]/cmdline), opens its corresponding memory mapping (/proc/[pid]/mem), and scrapes it entirely. It executes a precise command string designed to look for secrets in raw memory:
By targeting the runner’s raw memory, the worm completely bypasses GitHub’s built-in log masking utilities, extracting the active GITHUB_TOKEN, repository secrets, environment variables, and organization-wide credentials in pure, unmasked plaintext.
Beyond active memory, the daemonized background process systematically combs the host filesystem across 130 known file paths. It targets:
- Cloud Environments: Credentials for AWS, GCP, Azure, and Terraform.
- Developer Tools: Private keys, config files, and tokens for SSH, Kubernetes, Vault, and local .npmrc profiles.
- AI Tooling & Communications: Active tokens for Claude (~/.claude.json) and Slack/Discord cookies.
- Cryptocurrency Wallets: Physical wallet data for Bitcoin, Ethereum, and Electrum.
On Linux CI runner environments, the worm ensures it has total dominance by writing a passwordless sudoers rule to the host system (echo ‘runner $ALL=(ALL)$ NOPASSWD:ALL’ > /mnt/runner), immediately elevating its context from a restricted service account to full root access.
Once the data is harvested, the worm locks down persistence by nesting itself into modern AI and development workflows. It injects a SessionStart hook into .claude/settings.json to trigger execution every time a developer invokes Claude Code, drops persistent tasks into VS Code configurations (.vscode/tasks.json), and plants a compromised codeql.yml workflow file designed to automatically exfiltrate repository secrets on all subsequent code pushes or deployment events.
The worm is not just stealing these secrets—it is weaponizing them autonomously. Using the exfiltrated GitHub tokens, the worm has automatically spawned a massive infrastructure footprint. As of writing, over 2,500 public GitHub repositories have been created dynamically by the worm.
The entire operation leaves behind an explicit, thematic calling card. Each automated repository is named after paired terminology from Frank Herbert’s Dune universe (such as atreides-sandworm or mentat-ghola) and labeled with a reversed campaign marker string: “niagA OG EW ereH : duluH-iahS”. Spelled forward, it delivers a chilling message from the attacker: “Shai-Hulud: Here We Go Again.”
To guarantee the stolen data makes it home, the worm relies on a split exfiltration design:
- The Primary Dead-Drop: Stolen secrets are encrypted with a unique PBKDF2-derived key and committed straight into a dead-drop branch within the legitimate, heavily trafficked antvis/G2 repository via the official GitHub REST API. To blends in with normal automated workflows, the traffic mimics a standard Python user-agent (python-requests/2.31.0) and embeds an explicit marker within the git commit messages to allow the attacker to parse the data: IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner.
- The Fallback C2: If the GitHub API path fails, the malware establishes a direct TLS connection to t.m-kosche.com:443, pushing data to the path api/public/otel/v1/traces. This specific path was chosen to mimic authentic OpenTelemetry observability traffic, which is heavily whitelisted by corporate network filters.
Organizations must assume immediate compromise if any package from the @antv namespace or related utility packages maintained by atool were introduced to local machines or CI/CD pipelines over the last 24–48 hours.
StepSecurity advises the following strict recovery protocol:
- Audit Lockfiles: Immediately grep your package-lock.json, pnpm-lock.yaml, or yarn.lock for references to @antv/, echarts-for-react, timeago, jest-canvas-mock, or jest-date-mock. Hunt for the Payload: Scan your local folders for heavy index.js artifacts exceeding 400 KB or search for unauthorized instances of @antv/setup within package dependencies.
- Clean Configuration Files: Check your local repositories for unauthorized structural changes via git diff on .claude/settings.json, .vscode/tasks.json, and .github/workflows/codeql.yml. Wipe out malicious files like .claude/setup.mjs and .vscode/setup.mjs immediately.
- Nuclear Secret Rotation: Because the Runner.Worker memory scraper extracts masked variables in plaintext, every single secret exposed to an active build environment must be rotated immediately. This includes AWS/GCP cloud keys, internal npm publishing tokens, corporate Slack/Discord tokens, and GitHub Personal Access Tokens.
- Secure Cryptocurrency Holdings: If compromised developer machines house hot crypto wallets (~/.bitcoin/ or ~/.ethereum/), transfer assets to isolated, clean wallets immediately.
Support Our Threat Intelligence
If you find our CVE report and cybersecurity news helpful, consider supporting our work.