Light bulb Limited Spots Available: Secure Your Lifetime Subscription on Gumroad!

May 31, 2026 · 7 min read

Microsoft Caught 14 OpenSearch Typosquats Stealing CI/CD Secrets

An npm maintainer named vpmdhaj (a39155771@gmail.com) published 14 packages in a four-hour window on May 28, 2026, each spoofing the legitimate opensearch-project GitHub repository in its package.json. Every one ships a Bun-compiled 195 KB credential harvester that runs on npm install and walks out with AWS IAM credentials, HashiCorp Vault tokens, and GitHub Actions secrets.

The pattern is now boring. Pick a category of packages that mid-tier developers reach for without checking provenance—OpenSearch tooling, ElasticSearch helpers, DevOps utilities, environment-config managers—publish 14 lookalikes inside a single coffee-break window, point the repository field at the legitimate upstream's GitHub URL so the registry page looks plausible, and let npm's lifecycle hooks do the rest. On May 28, 2026, Microsoft's Defender for Cloud team caught a maintainer named vpmdhaj doing exactly that. The harvester underneath is 195 KB of compiled Bun, purpose-built for CI/CD environments where the credentials live in environment variables and the instance metadata service answers without authentication.

Key Takeaways

  • Microsoft's Defender for Cloud Security Research team disclosed the campaign on May 28, 2026 after observing the npm maintainer vpmdhaj (a39155771@gmail.com) publish 14 malicious packages in a single four-hour window the same day.
  • The packages typosquat well-known OpenSearch, ElasticSearch, DevOps, and environment-configuration libraries. Each package.json spoofs the homepage and repository fields with URLs pointing to the legitimate opensearch-project GitHub organization to defeat surface-level review.
  • All 14 ship the same install-time stager via npm preinstall hook and the same Bun-compiled ~195 KB credential harvester second stage. No user code needs to import the package; npm install alone is enough to detonate.
  • The harvester targets AWS (EC2 IMDS, ECS task role credentials, Secrets Manager across 16+ regions), HashiCorp Vault tokens, GitHub Actions credentials, npm publish tokens, and arbitrary CI/CD pipeline secrets accessible from environment variables.
  • This is the third major npm supply chain wave in two weeks, following the May 19 Mini Shai-Hulud burst that hit 323 packages in an hour and the TanStack OIDC token-poisoning attack on May 13.
A developer's desk at night with an open laptop showing blurred lines of code, a coffee mug, scattered index cards, and a small succulent plant, indigo and blue tones

Which 14 Packages Are Malicious?

Per Microsoft's writeup, the campaign published a mix of scoped and unscoped packages. Scoped variants under the vpmdhaj user namespace included @vpmdhaj/elastic-helper, @vpmdhaj/devops-tools, @vpmdhaj/opensearch-setup, and @vpmdhaj/search-setup. The unscoped lookalikes—the most dangerous because a typo in npm install can land them in a real project—were opensearch-security-scanner, opensearch-setup, opensearch-setup-tool, opensearch-config-utility, search-engine-setup, search-cluster-setup, elastic-opensearch-helper, vpmdhaj-opensearch-setup, env-config-manager, and app-config-utility.

npm has removed all 14 packages following Microsoft's disclosure. Any project that installed one of these names between approximately 14:00 and 18:00 UTC on May 28 should treat the build host as compromised, rotate every credential available to that host, and review CI/CD audit logs for the same window.

How Does the Install-Time Stager Work?

Each package's package.json defines an npm preinstall hook. Preinstall hooks fire automatically when a developer runs npm install, before any application code is touched. The hook unpacks the Bun-compiled second-stage binary from a base64 blob embedded in the package, writes it to a temporary path, and executes it with the privileges of the calling user. For a developer running locally, that's their own user account. For a CI/CD runner, that's whatever service account the build is running as—typically with broad cloud privileges by design.

The second stage is compiled with Bun rather than packaged as plain JavaScript. That choice is deliberate. A Bun-compiled binary is harder to triage at a glance—JavaScript review tools don't read it as source, antivirus signatures haven't caught up to Bun-compiled malware, and the binary is small enough (195 KB) to embed in a package without raising size-anomaly flags.

What Does the 195 KB Harvester Actually Take?

The harvester is engineered for the cloud and CI/CD world specifically. It does not try to be a general-purpose stealer. It does five things, in order:

  1. Polls the AWS Instance Metadata Service (169.254.169.254) for credentials. On EC2 with IMDSv1 (or improperly hardened IMDSv2), this returns the IAM role's temporary access key, secret key, and session token—no exploit required, just an HTTP GET.
  2. Hits the ECS task role endpoint ($AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) for container-scoped credentials when running inside an ECS task.
  3. Iterates AWS Secrets Manager across more than 16 regions, listing every secret the captured IAM role can read and exfiltrating contents.
  4. Reads HashiCorp Vault tokens from the standard environment variables (VAULT_TOKEN, VAULT_ADDR) and any ~/.vault-token file the build user can access.
  5. Scans process environment for CI/CD secrets: GITHUB_TOKEN, NPM_TOKEN, GitLab CI variables, CircleCI tokens, Buildkite agent tokens, anything with the word "TOKEN", "KEY", or "SECRET" in the variable name.

Exfiltration is over HTTPS to an attacker-controlled endpoint encoded directly in the binary. The harvester does not attempt persistence on the host; the credentials are the persistence.

Why Does Typosquatting Still Work in 2026?

Because the registry has not made it cost anything to publish a lookalike. A new npm user can ship a package within minutes of creating an account. The registry's spam controls catch a meaningful percentage of typosquats but not at the speed an active campaign moves. Microsoft caught vpmdhaj within hours; the attacker, however, only needed any project's npm install command to misspell opensearch once. Spelling errors are very common.

The deeper issue is that npm's design treats repository and homepage fields as freeform metadata. A package can claim to live in the opensearch-project organization without proving anything. Tooling exists to verify GitHub provenance (npm's own --provenance flag, Sigstore signatures) but adoption is voluntary and the typosquat campaign explicitly opts out.

What Should Developer Teams Do Right Now?

Four steps, in order of urgency:

  1. Audit the npm install history of every CI/CD runner and developer workstation for any of the 14 names against the timestamps in Microsoft's IoC release. If a hit is found, treat that host as compromised.
  2. Enforce IMDSv2 with hop-limit 1 on every EC2 instance. IMDSv2 with a strict hop limit prevents the most common metadata-credential theft path used by this harvester. AWS has documentation; the change is one Terraform field.
  3. Scope IAM roles tightly. A build role that can read every secret in Secrets Manager across 16 regions is the exact precondition this campaign monetizes. Per-pipeline roles with per-secret read grants reduce blast radius from "everything" to "this one build."
  4. Pin dependencies and run npm ci in CI against a known-good lockfile. npm install resolves names dynamically and is the path that catches typosquats. npm ci only installs what the lockfile already verified.

For application developers, the operational threat extends past the build host. Stolen AWS keys feed phishing infrastructure (Mailgun and SES accounts created with hijacked credentials), npm publish tokens become the next supply-chain wave, and GitHub Actions tokens get reused to plant backdoors in downstream repos. The phishing emails that arrive in users' inboxes after one of these waves are often sent from legitimate-looking infrastructure standing up on someone else's stolen IAM role. Gblock strips the tracking pixels in those marketing-style phishing emails, so when the wave does land in Gmail, the attacker can't tell which inboxes are alive.

How Bad Is the npm Ecosystem Right Now?

Three high-impact npm waves in 16 days is the answer. The Mini Shai-Hulud wave on May 19 published 639 malicious versions across 323 packages in a single hour from a compromised maintainer account. The TanStack attack on May 13 used a stolen OIDC token in a runner's process memory to push 84 malicious packages through the legitimate release pipeline. And now vpmdhaj's typosquats add 14 more.

The economy underneath is straightforward: cloud credentials are worth far more on resale than any front-page mainstream malware, and CI/CD systems have a near-perfect concentration of those credentials. As long as npm install can execute arbitrary code with build-pipeline privileges on a runner with a privileged IAM role, the supply chain is the cheapest way to reach the credentials. None of that is fixable at the registry alone.

What Happens Next?

Two things to watch. First, the vpmdhaj credentials are likely already in resale. Cloud incident-response firms will see a measurable bump in Mailgun, SES, and S3 abuse over the next 30 days that traces back to AWS keys harvested out of CI/CD runners on May 28. Second, the Bun-compiled second-stage pattern is going to repeat. Bun-compiled malware is genuinely harder to static-analyze than plain Node.js code, and now that one campaign has proven the tooling works at registry scale, the next wave will look the same.

The honest answer for defenders is that the registry is not going to fix this for you. Pin your dependencies, scope your IAM roles, and assume every npm install is a code-execution event until proven otherwise.

Stop Email Tracking in Gmail

Spy pixels track when you open emails, where you are, and what device you use. Gblock blocks them automatically.

Try Gblock Free for 30 Days

No credit card required. Works with Chrome, Edge, Brave, and Arc.