Compromised npm packages put CI/CD secrets at risk

Microsoft says malicious @antv npm packages targeted GitHub Actions and cloud credentials through install-time execution.

2026-05-22 GIGATAP Team #security
#npm#supply-chain#ci-cd

What Microsoft says happened#

Microsoft says it identified an active supply-chain attack in the npm ecosystem involving compromised @antv packages. According to Microsoft, a threat actor compromised a maintainer account and published malicious versions of widely used data-visualization packages.

The affected package family matters because @antv libraries sit inside charting and dashboard stacks. Microsoft says the compromise propagated through dependency chains into downstream libraries, including one with more than 1 million weekly downloads. That is the core supply-chain problem: the first compromised package is not always where the impact stops.

The malicious payload ran during npm install through a preinstall hook. Microsoft describes it as an obfuscated JavaScript file of about 499 KB. Its apparent focus was CI/CD environments, especially GitHub Actions on Linux. The payload included checks that caused it to exit in some paths when it was not running in that environment.

Microsoft also notes that the @antv account authors later confirmed in a repository ticket that the situation was resolved. That does not erase downstream exposure. It narrows the immediate package-publishing issue, while leaving teams to answer a harder question: did any build runner install the malicious versions while secrets were present?

Why this is more than a bad package release#

Many npm incidents stop at install-time execution, token theft, or typosquatting. This one is more specific. Microsoft’s analysis describes tooling aimed at CI/CD credential theft across several platforms.

The payload reportedly targeted secrets or tokens tied to:

  • GitHub and GitHub Actions
  • Amazon Web Services
  • HashiCorp Vault
  • npm
  • Kubernetes
  • 1Password

That list is the risk model. A build runner often has short-lived access to code, cloud APIs, package registries, deployment keys, and secret stores. If malware runs there, it may not need to compromise a developer laptop. The pipeline already has the trust it wants.

Microsoft says the payload attempted to enumerate GitHub repository and organization secrets, scan for personal access tokens and installation tokens, interact with AWS metadata services, read AWS-related files and environment variables, query Secrets Manager, search for Vault tokens in multiple local paths, read Kubernetes service account tokens, and interact with the 1Password CLI.

The GitHub Actions angle is especially important. Microsoft says the payload located the Runner.Worker process on Linux by scanning /proc, then attempted to extract secrets from process memory. That is a different class of attack than simply printing environment variables. Secret masking protects logs. It does not automatically protect a process from memory inspection by code already running on the same runner with enough access.

Microsoft also describes an attempted privilege escalation path involving a passwordless sudo rule through a bind mount, plus DNS manipulation through /etc/hosts. Those details point to an attacker trying to improve local control of the runner before exfiltration.

How the payload tried to hide and move data#

Microsoft describes several layers of obfuscation. The payload replaced the legitimate index.js with a single-line obfuscated script. It used a large rotated array of Base64-encoded strings and runtime decoding. Critical strings such as command-and-control domains and environment variable names were encrypted and decrypted only at runtime using a custom PBKDF2 and SHA-256-based mechanism.

That does not make the malware novel by itself. It does raise the cost of quick triage. A maintainer or consumer looking at the package diff would see a dense blob, not readable application code.

The execution chain also matters. Microsoft describes a path of node → shell → bun → payload, with the Bun runtime installed if absent. That gives defenders another thing to check: unexpected Bun installation or execution inside CI jobs that did not previously use it.

For exfiltration, Microsoft says the payload used two channels. The primary path was HTTPS to an encrypted command-and-control domain over port 443, with a DNS pre-check and health probe. A fallback path used the Git Data API, creating blobs, trees, or commits in victim repositories on non-protected branches.

Microsoft also reports that the malware created public repositories under victim accounts with a reversed description string: niagA oG eW ereH :duluH-iahS. More than 2,200 such repositories had been observed at the time of Microsoft’s writing.

That repository artifact may help defenders identify exposure. It should not be treated as the only signal. If the payload had multiple exfiltration routes, absence of the public repository marker does not prove a runner was safe.

What teams should check first#

The practical question is not whether a project directly imports @antv. The first question is whether any dependency tree pulled a malicious version during the exposure window. Microsoft’s post should be used as the source for package indicators and technical details, since the exact affected versions and downstream paths matter.

Teams should start with build and dependency evidence:

  • Review lockfiles and package manager logs for @antv packages and affected downstream dependencies.
  • Check CI job history for installs that occurred during the relevant window.
  • Look for unexpected preinstall execution tied to the package path.
  • Search runner logs and images for unexpected Bun installation or execution.
  • Identify builds that ran on GitHub Actions Linux runners with secrets available.

Then move to credential exposure, not only package cleanup:

  • Rotate GitHub tokens, npm tokens, cloud credentials, and deploy keys that were available to affected jobs.
  • Review GitHub repository, organization, and Actions secret access patterns.
  • Check AWS CloudTrail and Secrets Manager activity for unusual enumeration or reads.
  • Inspect Vault audit logs for unexpected token use, local token access, or secret listing.
  • Review Kubernetes API activity from CI identities.
  • Check for unexpected public repositories, commits, blobs, or branches created by automation accounts.

If self-hosted runners were used, treat them as higher-risk until inspected or rebuilt. Ephemeral hosted runners reduce persistence risk, but they do not remove the risk of secret theft during the job.

What not to overclaim#

The source material does not support every possible conclusion. Microsoft describes an active supply-chain attack and detailed payload capabilities. That is not the same as proving every downstream user had secrets stolen.

There are several separate questions defenders need to keep apart:

  • Was a malicious version present in the dependency tree?
  • Did a CI job install it?
  • Did the environment match the payload’s execution gates?
  • Were secrets present and accessible at that time?
  • Did exfiltration succeed through HTTPS or the Git Data API?

A yes to the first question does not automatically answer the last one. But a yes to the first three should be treated seriously, because the payload was built for exactly that setting.

The larger lesson for CI/CD trust#

This incident fits a pattern. Package ecosystems are not just developer convenience layers. They are execution paths into build systems. A package install can become code execution inside the place where organizations concentrate credentials.

That makes CI/CD dependency policy a security boundary. Lockfiles, provenance, token scoping, secret minimization, and ephemeral runners are not paperwork controls. They decide how much damage one compromised maintainer account can do.

The sharpest takeaway is simple: do not evaluate npm supply-chain incidents only by application runtime impact. Check the build path. That is where the secrets were.