# Phantom Gyp Miasma worm hits @vapi-ai/server-sdk and the jagreehal portfolio via binding.gyp

> Between 23:30 UTC on 2026-06-03 and ~01:30 UTC on 2026-06-04 the Miasma worm published a malicious 157-byte `binding.gyp` payload through 57 npm packages and 286+ versions, starting at `@vapi-ai/server-sdk` (~408k weekly downloads) and cascading across the jagreehal maintainer's `autotel-*`, `awaitly-*`, `ai-sdk-*`, `executable-stories-*`, `node-env-resolver-*`, and `wrangler-deploy` portfolio. GitHub Advisories backfilled the full affected-version set across the `autotel-*` family and the wider `awaitly-*` portfolio on 2026-06-29 / 2026-06-30 (16 new `autotel-*` GHSAs plus expanded `awaitly` / `awaitly-mongo` / `awaitly-libsql` / `awaitly-analyze` ranges).

- Published: 2026-06-03
- Last updated: 2026-08-28
- Severity: critical
- Kind: Compromise - A legitimate, already-used package, maintainer account, CI pipeline, or release tag was hijacked and a malicious version was published under a name people already depend on.
- Ecosystems: npm
- Scope: 26 packages, 167 compromised versions
- Tags: worm, credential-theft, ci-cd-compromise, maintainer-takeover, obfuscation, prompt-injection
- Threat actor: TeamPCP
- Also known as: Miasma v2, Phantom Gyp, binding.gyp worm, Mini Shai-Hulud
- Detected by: StepSecurity, Socket, Snyk, Sonatype, Semgrep, Chainguard, Corgea, Akamai, Wiz, OX Security
- Incident ID: npm-2026-06-03-phantom-gyp-vapi-jagreehal

## Affected packages (26)

Only the exact versions listed were named by the source advisories. Other versions are not implicated.

| Package | Ecosystem | Compromised versions |
|---|---|---|
| [@vapi-ai/server-sdk](https://dependencywatch.io/package/npm/@vapi-ai/server-sdk) | npm | 0.11.1, 0.11.2, 1.2.1, 1.2.2 |
| [ai-sdk-ollama](https://dependencywatch.io/package/npm/ai-sdk-ollama) | npm | 0.13.1, 1.1.1, 2.2.1, 3.8.5 |
| [autotel-backends](https://dependencywatch.io/package/npm/autotel-backends) | npm | 2.12.26 |
| [autotel-cli](https://dependencywatch.io/package/npm/autotel-cli) | npm | 0.8.14 |
| [autotel-drizzle](https://dependencywatch.io/package/npm/autotel-drizzle) | npm | 0.0.27 |
| [autotel-eventcatalog](https://dependencywatch.io/package/npm/autotel-eventcatalog) | npm | 1.0.1, 2.0.1, 3.0.1, 4.0.2, 5.0.1 |
| [autotel-hono](https://dependencywatch.io/package/npm/autotel-hono) | npm | 0.4.26 |
| [autotel-mcp](https://dependencywatch.io/package/npm/autotel-mcp) | npm | 0.1.14, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.1, 17.0.2, 18.0.1, 19.0.1, 20.0.1, 21.1.1, 22.0.1, 23.0.1, 24.0.1, 25.0.1, 26.0.2, 27.0.1, 28.0.3, 29.0.1 |
| [autotel-mcp-instrumentation](https://dependencywatch.io/package/npm/autotel-mcp-instrumentation) | npm | 29.0.2, 30.0.5, 31.0.1, 32.0.1, 33.0.2, 34.0.1 |
| [autotel-mongoose](https://dependencywatch.io/package/npm/autotel-mongoose) | npm | 0.0.3, 1.0.2, 2.0.5, 3.0.1, 4.0.1, 5.0.2, 6.0.1 |
| [autotel-pact](https://dependencywatch.io/package/npm/autotel-pact) | npm | 0.2.2, 1.0.3 |
| [autotel-playwright](https://dependencywatch.io/package/npm/autotel-playwright) | npm | 0.4.32 |
| [autotel-plugins](https://dependencywatch.io/package/npm/autotel-plugins) | npm | 0.19.26 |
| [autotel-sentry](https://dependencywatch.io/package/npm/autotel-sentry) | npm | 0.5.13 |
| [autotel-subscribers](https://dependencywatch.io/package/npm/autotel-subscribers) | npm | 4.1.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.1.1, 15.0.1, 16.0.2, 17.0.1, 18.0.3, 19.0.1, 20.0.1, 21.0.1, 22.0.2, 23.0.2, 24.0.1, 25.0.1, 26.0.1, 27.0.2, 28.0.2, 29.0.6, 30.0.4, 31.1.4 |
| [autotel-tanstack](https://dependencywatch.io/package/npm/autotel-tanstack) | npm | 1.13.27 |
| [autotel-vitest](https://dependencywatch.io/package/npm/autotel-vitest) | npm | 0.4.26 |
| [autotel-web](https://dependencywatch.io/package/npm/autotel-web) | npm | 1.12.2 |
| [awaitly](https://dependencywatch.io/package/npm/awaitly) | npm | 1.33.3 |
| [awaitly-analyze](https://dependencywatch.io/package/npm/awaitly-analyze) | npm | 0.24.2, 1.1.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1 |
| [awaitly-libsql](https://dependencywatch.io/package/npm/awaitly-libsql) | npm | 0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.1, 21.0.1, 22.0.1 |
| [awaitly-mongo](https://dependencywatch.io/package/npm/awaitly-mongo) | npm | 0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.1.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1 |
| [awaitly-postgres](https://dependencywatch.io/package/npm/awaitly-postgres) | npm | 0.1.1, 1.0.1, 2.0.1, 3.0.2, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1 |
| [awaitly-visualizer](https://dependencywatch.io/package/npm/awaitly-visualizer) | npm | 1.0.1 |
| [node-env-resolver](https://dependencywatch.io/package/npm/node-env-resolver) | npm | 6.5.1 |
| [wrangler-deploy](https://dependencywatch.io/package/npm/wrangler-deploy) | npm | 1.5.5 |

## What happened

On 2026-06-03 at 23:30 UTC the Miasma operator (the same TeamPCP / Mini Shai-Hulud lineage behind the 2026-06-01 `@redhat-cloud-services` wave two days earlier) published four malicious versions of `@vapi-ai/server-sdk`, the official Vapi.ai voice-AI server SDK with ~408,000 weekly downloads. Within an hour the worm pivoted to the unrelated `jagreehal` maintainer account and used the stolen publish token to enumerate every package that account owned, republishing a tampered `X.Y.(Z+1)` patch on every released major branch. The whole campaign was over in under two hours. Final tally: 57 packages, 286+ malicious versions, two distinct maintainer takeovers.

## Phantom Gyp: a 157-byte install-time RCE

Instead of the usual `preinstall` / `postinstall` lifecycle script hooked off `package.json`, the worm ships a minimal `binding.gyp` file. npm treats `binding.gyp` as a signal that the package contains native C/C++ code and unconditionally invokes `node-gyp rebuild` during install. The attacker abuses gyp's command-substitution syntax to embed a shell command that runs `node index.js` (or a Bun bootstrap), then returns a fake source filename so the build succeeds with no visible error. Almost every install-time security scanner (Socket, Snyk, npm audit, JFrog) hooks the lifecycle scripts and never inspects `binding.gyp`, so the entire exposure window opened and closed before any registry advisory could fire. As of disclosure there is no CVE, GHSA, or OSV record covering the wave.

## Payload

The `index.js` stage downloads a Bun runtime, executes a heavily obfuscated JavaScript credential stealer (the same family used in the 2026-04-30 `@cap-js` SAP wave and the 2026-05-11 TanStack burst), then harvests AWS IMDSv2, GCP metadata, Azure managed-identity tokens, Kubernetes service-account tokens, HashiCorp Vault reads, GitHub Actions OIDC tokens, npm/PyPI/RubyGems publish tokens, SSH keys, Docker config, and `.env` files. Exfil is via attacker-controlled GitHub repos created from the stolen `gh` tokens, and the worm injects a `.github/workflows/*.yml` step into every repo it can push to so the next CI run re-detonates the chain. The same payload drops backdoor MCP/instruction-override configs into `.claude/`, `.cursor/`, and `.gemini/` directories so AI-assisted edits inside a poisoned project can be silently steered.

## Maintainer impact

The `@vapi-ai` org takeover yielded a single high-traffic package (`@vapi-ai/server-sdk`, four malicious versions including `0.11.1`). The `jagreehal` takeover yielded the long tail: the `autotel-*` OpenTelemetry framework (24 packages including `autotel-cli`, `autotel-cloudflare`, `autotel-aws`, `autotel-edge`), the `awaitly-*` async-workflow stack (7 packages, each republished across every released major as `X.Y.(Z+1)`), the `ai-sdk-*` Vercel AI SDK helpers (including `ai-sdk-ollama` at ~120k weekly downloads with malicious `0.13.1`/`1.1.1`/`2.2.1`/`3.8.5`), the `executable-stories-*` BDD test runners, the `node-env-resolver` family, and the `wrangler-deploy` Cloudflare Workers tooling. The clean republishes shipped 2026-06-04 to 2026-06-06 carry deprecation notices on the malicious patches reading `SECURITY: compromised supply-chain build (2026-06-04 worm) - do not use; upgrade to a known-good release.`

- Eighth distinct wave in the Shai-Hulud / Miasma lineage since 2025-09; second wave in three days following the 2026-06-01 `@redhat-cloud-services` compromise.
- No GHSA / OSV / npm advisory at disclosure - the worm landed and was unpublished/deprecated faster than the advisory pipelines could ingest, so the npm package-deprecation field is currently the only registry-level signal.
- Downstream coverage: StepSecurity (named the technique "Phantom Gyp"), Snyk (tracker entry node-gyp-supply-chain-compromise-june-2026), Sonatype, Semgrep, Chainguard, Corgea, Akamai, Socket, Wiz, OX Security, and Phoenix Security all republished within ~36 hours.

## 2026-06-29 / 2026-06-30 advisory backfill

GitHub Advisories caught up on the long tail of the jagreehal portfolio with 21 new GHSA records published 2026-06-29 and 2026-06-30, all CWE-506 / malware-classified. Coverage now includes the full `autotel-*` framework - `autotel-cli` (`0.8.14`), `autotel-web` (`1.12.2`), `autotel-vitest` (`0.4.26`), `autotel-hono` (`0.4.26`), `autotel-tanstack` (`1.13.27`), `autotel-playwright` (`0.4.32`), `autotel-sentry` (`0.5.13`), `autotel-plugins` (`0.19.26`), `autotel-drizzle` (`0.0.27`), `autotel-backends` (`2.12.26`), `autotel-pact` (`0.2.2`/`1.0.3`), `autotel-eventcatalog` (5 patches), `autotel-mongoose` (7 patches), `autotel-mcp-instrumentation` (6 patches), `autotel-mcp` (28 patches), and `autotel-subscribers` (28 patches). The `awaitly-*` portfolio was re-confirmed and extended: `awaitly` itself (`<= 1.33.3`), and the per-major patch counts for `awaitly-mongo` (24), `awaitly-libsql` (23), and `awaitly-analyze` (9) now match the registry-side unpublish trail. The pattern across every package is identical to the original wave: a single `X.Y.(Z+1)` malicious patch on each released major branch, then a clean republish at `X.Y.(Z+2)` once the maintainer regained control.

## Impact

- Install-time RCE: npm auto-invokes `node-gyp rebuild` when it sees `binding.gyp`, so `npm install`/`npm ci` executes the worm before any lifecycle script runs
- Credential theft from CI/CD runners and developer workstations: GitHub Actions OIDC, AWS, GCP, Azure, HashiCorp Vault, Kubernetes service accounts, SSH keys, npm/PyPI/RubyGems publish tokens, Docker configs
- Self-propagating: stolen npm tokens are used to enumerate every package a victim maintainer owns and republish a poisoned `binding.gyp` patch (`X.Y.(Z+1)`) on every released major
- Forged provenance: the worm re-uses the victim's trusted publisher (GitHub OIDC) so the malicious tarballs ship with valid SLSA provenance and Sigstore attestations
- CI/CD persistence: malicious GitHub Actions workflow files are injected into every repo the stolen token can push to, so a single re-run re-detonates the campaign
- AI-assistant tampering: backdoor config files are dropped for Claude Code, Cursor, and Gemini so subsequent AI-assisted edits inside a poisoned project can be steered by the attacker

## What to do

1. Pin and reinstall: remove `node_modules`/lockfile entries and pin to the post-incident clean release (e.g. `@vapi-ai/server-sdk` >= 1.2.0, `ai-sdk-ollama` >= 3.8.6, `autotel-cli` >= 0.8.15, `node-env-resolver` >= 6.5.2, `wrangler-deploy` >= 1.5.6, `awaitly-*` >= the post-2026-06-04 clean republish)
2. Treat any developer host or CI runner that ran `npm install` against an affected version between 2026-06-03 23:30 UTC and 2026-06-04 02:00 UTC as fully compromised; rotate every credential reachable from that host
3. Rotate npm tokens, GitHub Actions OIDC trust, AWS/GCP/Azure keys, Vault tokens, Kubernetes service-account tokens, and SSH keys held by impacted maintainers
4. Audit recent npm publish history under your maintainers for unexpected `X.Y.(Z+1)` patch bumps published between 2026-06-03 and 2026-06-04
5. Hunt for `binding.gyp` files in repos that have no native code, and for unexpected GitHub Actions workflows pushed within the exposure window
6. Inspect AI-assistant config files (`.claude/`, `.cursor/`, `.gemini/`) inside cloned victim repos for unexpected MCP / instruction overrides

## Check your own dependencies

- Check a package-lock.json against this incident: https://dependencywatch.io/check/package-lock-json

The scan runs entirely in the browser; lockfile contents are never uploaded.

## References

- [Supply chain compromise: malicious binding.gyp worm harvests CI/CD secrets and injects into GitHub Actions workflows (Issue #975)](https://github.com/jagreehal/ai-sdk-ollama/issues/975) - jagreehal/ai-sdk-ollama
- [@vapi-ai/server-sdk npm registry entry (compromised 0.11.1 deprecated)](https://www.npmjs.com/package/@vapi-ai/server-sdk) - npm
- [ai-sdk-ollama npm registry entry](https://www.npmjs.com/package/ai-sdk-ollama) - npm
- [wrangler-deploy npm registry entry (compromised 1.5.5 deprecated)](https://www.npmjs.com/package/wrangler-deploy) - npm
- [awaitly-postgres npm registry entry (compromised 0.1.1–12.0.1 deprecated)](https://www.npmjs.com/package/awaitly-postgres) - npm
- [GHSA-3729-344x-9v28 - autotel-cli malware advisory](https://github.com/advisories/GHSA-3729-344x-9v28) - GitHub
- [GHSA-78g2-45pm-5862 - autotel-web malware advisory](https://github.com/advisories/GHSA-78g2-45pm-5862) - GitHub
- [GHSA-m9j7-x8ww-5jwr - ai-sdk-ollama malware advisory](https://github.com/advisories/GHSA-m9j7-x8ww-5jwr) - GitHub
- [GHSA-c8c9-7f3h-7c76 - awaitly malware advisory](https://github.com/advisories/GHSA-c8c9-7f3h-7c76) - GitHub
- [GHSA-mjhg-2cvf-w2p4 - @vapi-ai/server-sdk formal advisory (backfilled 2026-08-27; covers 0.11.1, 0.11.2, 1.2.1, 1.2.2)](https://github.com/advisories/GHSA-mjhg-2cvf-w2p4) - GitHub

---

Canonical page: https://dependencywatch.io/incident/npm-2026-06-03-phantom-gyp-vapi-jagreehal
Markdown version: https://dependencywatch.io/incident/npm-2026-06-03-phantom-gyp-vapi-jagreehal.md
Site index for agents: https://dependencywatch.io/llms.txt
DependencyWatch.io is operated by Precursor Security (https://precursorsecurity.com).
