# Binding.gyp "Phantom Gyp" Supply Chain Attack (Miasma Worm) Enables CI/CD Worm Propagation Across 57 npm Packages

> The TeamPCP-linked Miasma worm published trojanized versions of 57 npm packages (286+ malicious versions) using a novel "Phantom Gyp" technique that abuses binding.gyp's node-gyp command-substitution syntax to execute a multi-stage credential-stealing payload during npm install, bypassing preinstall/postinstall script scanners. The malware harvests AWS/GCP/Azure/Vault/Kubernetes/GitHub Actions credentials, forges Sigstore SLSA provenance, backdoors AI coding assistants (Claude Code, Cursor, Gemini, VS Code), and self-propagates by republishing from every compromised maintainer account it can reach.

- **Published:** 2026-06-04T00:00:00Z
- **Last reviewed:** 2026-06-04T00:00:00Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-1234
- **ID:** TL-2026-1234
- **Severity:** HIGH
- **Category:** SUPPLY_CHAIN
- **Status:** ACTIVE
- **Actor:** TeamPCP
- **Detections:** 9 · **IOCs:** 27 (full data via the Threadlinqs MCP server — Purple tier)
- **CVEs:** CVE-2026-45321, CVE-2026-48027

## Description

On 2026-06-03, security researchers at StepSecurity identified a follow-on variant of the Miasma npm supply-chain worm, dubbed "Phantom Gyp," that abandoned the preinstall/postinstall lifecycle-script vector used by earlier Shai-Hulud-lineage worms in favor of a previously overlooked execution primitive: the binding.gyp native-addon build configuration file consumed by node-gyp. A minimal 157-byte binding.gyp embedded in trojanized package versions declares a `sources` array entry using GYP's `<!(...)` command-substitution syntax — `"sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]` — which node-gyp evaluates as a shell command during the automatic `node-gyp rebuild` step npm performs whenever a package ships a binding.gyp, regardless of whether the package declares an explicit install script. Because binding.gyp is build metadata rather than a package.json script entry, script-scanning security tooling and SCA products largely failed to flag it, creating a detection blind spot the attackers exploited deliberately.

The payload chain is heavily obfuscated: a legitimate-looking package ships an oversized (4-5 MB) `index.js` at its package root — never imported by the actual application code, which remains untouched in `dist/` — that is first unwrapped through a ROT-N Caesar cipher (rotation values observed at 9, 14, 15, 18, 19, and 20 across samples) applied to a ~1.3 million character array, then decrypted with AES-128-GCM using hardcoded keys/IVs, then used to download and execute a standalone Bun JavaScript runtime binary (v1.3.13, sourced directly from the legitimate `github.com/oven-sh/bun` GitHub Releases CDN) in under one second. Running the ~650-750 KB final-stage stealer under Bun rather than Node.js specifically defeats process-monitoring EDR/XDR rules scoped to `node` child processes spawned during `npm install`.

Once running, the stealer systematically harvests CI/CD and cloud credentials: AWS access keys/secret keys/session tokens and IMDSv2 metadata, GCP service-account keys and `GOOGLE_APPLICATION_CREDENTIALS`, Azure managed-identity and IMDS tokens, HashiCorp Vault tokens (Kubernetes-auth and AWS-auth paths, plus local token files), Kubernetes service-account tokens, and local secrets stores (1Password, pass, gopass). Inside GitHub Actions runners specifically, the malware escalates via `sudo python3` and reads `/proc/[pid]/mem` of the `Runner.Worker` process, grepping for the JSON pattern GitHub uses to store unmasked secret values (`"[^"]+":{"value":"[^"]*","isSecret":true}`), completely bypassing GitHub's log-masking protections for secrets referenced in the workflow.

For persistence and lateral compromise of the developer's own tooling, the malware commits backdoor files into accessible repositories using stolen GitHub tokens, with commit messages such as "This is required for proper IDE integration and dependency setup": `.claude/setup.mjs` (abusing Claude Code's SessionStart hook), `.cursor/rules/setup.mdc`, `.gemini/settings.json`, `.vscode/tasks.json` (using a `runOn: folderOpen` auto-execution trigger), and `.github/setup.js` for GitHub Actions workflow injection. This specifically targets developers using AI-assisted IDEs, since the backdoors execute automatically the next time a victim opens the poisoned repository.

Stolen data is exfiltrated over GitHub.com itself rather than attacker-registered domains, using GitHub's API as covert C2/dead-drop infrastructure: the malware creates private repositories under the attacker-controlled account `github.com/liuende501` (observed with 236 programmatically created repos, using Dune-themed — atreides, fedaykin, sardaukar — and mythology-themed — nemean-hydra-N, cerberus, chimera — naming conventions), encrypts harvested credentials with an embedded attacker RSA public key, and uploads them via the GitHub Contents API to paths of the form `repos/liuende501/{repo}/contents/results/results-{timestamp}.json`, spoofing a `python-requests/2.31.0` User-Agent despite running under Bun/Node. C2-liveness and coordination is performed via public GitHub commit-message keyword search (magic strings including "thebeautifulmarchoftime" and, in a later variant, "firedalazer"), and a stolen-token social-engineering deterrent string — "IfYouInvalidateThisTokenItWillNukeTheComputerOfTheOwner" — is embedded to discourage victims from revoking compromised tokens. Of 234 observed repo descriptions, 34 read "Miasma - The Spreading Blight" and 195 contain the reversed taunt "niagA oG eW ereH :duluH-iahS" ("Shai-Hulud: Here We Go Again"), referencing StepSecurity's prior public analysis of the Red Hat/Shai-Hulud-lineage Miasma compromise.

Self-propagation is cross-ecosystem and worm-like: on npm, the malware validates its stolen token via `registry.npmjs.org/-/whoami`, enumerates every package owned by that maintainer via the registry search API (`/v1/search?text=maintainer:`), injects the malicious binding.gyp and obfuscated index.js into each, and republishes — critically, forging valid-looking Sigstore SLSA v1 build provenance attestations by fraudulently obtaining Fulcio certificates and Rekor transparency-log entries via the OIDC token-exchange endpoint (`/-/npm/v1/oidc/token/exchange/`), making the compromised releases appear to carry legitimate cryptographic build provenance. A parallel RubyGems propagation path injects equivalent logic into `extconf.rb` (the RubyGems analogue of binding.gyp), generating fake `Makefile`/`CMakeLists.txt` scaffolding and reusing the identical Bun-runtime execution chain.

Attribution is to the threat cluster tracked as TeamPCP, which researchers assess is responsible for the broader 2026 Shai-Hulud/Mini Shai-Hulud npm supply-chain campaign lineage, including the May 2026 TanStack compromise (CVE-2026-45321, added to the CISA KEV catalog 2026-05-27) — the first documented malicious npm package to carry cryptographically valid SLSA Build Level 3 provenance — and the related Nx Console compromise (CVE-2026-48027). TeamPCP subsequently open-sourced their "Mini Shai-Hulud" worm framework on GitHub under a permissive license, which multiple vendors (Wiz, Microsoft, Unit 42) caution has decoupled TTP overlap from definitive attribution for later waves, since any actor can now reuse the framework. The Phantom Gyp/Miasma wave itself unfolded within a roughly two-hour window beginning 2026-06-03 ~23:30 UTC, first compromising the high-download `@vapi-ai/server-sdk` package (408,000+ monthly downloads) before rapidly hitting the `jagreehal`-maintained `ai-sdk-ollama` and 50+ related packages across the `autotel`, `awaitly`, `executable-stories`, `node-env-resolver`, `mountly`, and `wrangler-deploy` package families — a follow-on to an earlier 2026-06-01 wave that compromised 32+ `@redhat-cloud-services`-scoped packages via a compromised Red Hat employee account and malicious GitHub Actions workflow injection. A related but distinct campaign, "IronWorm," surfaced around the same period via the compromised `asteroiddao` npm account, using a Rust ELF preinstall binary with an eBPF kernel-level rootkit component and forged `claude@users.noreply.github.com` commit authorship to impersonate Anthropic's Claude Code.

npm has responded structurally: npm v12, shipping July 2026, changes default script-execution behavior to block install scripts (including implicit `node-gyp rebuild` for packages with a binding.gyp and no explicit install script) — directly closing the Phantom Gyp execution vector by default for future installs.

## MITRE ATT&CK

- T1586 Compromise Accounts
- T1585 Establish Accounts
- T1195.001 Compromise Software Dependencies and Development Tools
- T1195.002 Compromise Software Supply Chain
- T1199 Trusted Relationship
- T1059.007 JavaScript
- T1059.004 Unix Shell
- T1204.003 Malicious Image
- T1610 Deploy Container
- T1546 Event Triggered Execution
- T1543.001 Launch Agent
- T1098 Account Manipulation
- T1525 Implant Internal Image
- T1548.003 Sudo and Sudo Caching
- T1027 Obfuscated Files or Information
- T1140 Deobfuscate/Decode Files or Information
- T1036 Masquerading
- T1070 Indicator Removal
- T1553 Subvert Trust Controls
- T1684.001 Impersonation
- T1552.001 Credentials In Files
- T1555 Credentials from Password Stores
- T1003 OS Credential Dumping
- T1528 Steal Application Access Token
- T1539 Steal Web Session Cookie
- T1526 Cloud Service Discovery
- T1518 Software Discovery
- T1083 File and Directory Discovery
- T1057 Process Discovery
- T1072 Software Deployment Tools
- T1005 Data from Local System
- T1119 Automated Collection
- T1102 Web Service
- T1105 Ingress Tool Transfer
- T1132.001 Standard Encoding
- T1567 Exfiltration Over Web Service
- T1020 Automated Exfiltration
- T1560 Archive Collected Data
- T1657 Financial Theft

## Sources

- [Binding.gyp Supply Chain Attack Enables CI/CD Worm Propagation Across npm Packages](https://threats.wiz.io/all-incidents/bindinggyp-supply-chain-attack-enables-cicd-worm-propagation-across-npm-packages)
- [Miasma npm Supply Chain Attack: Self-Spreading Worm via Phantom Gyp](https://www.stepsecurity.io/blog/binding-gyp-npm-supply-chain-attack-spreads-like-worm)
- [Node-gyp Supply Chain Compromise | Snyk](https://snyk.io/blog/node-gyp-supply-chain-compromise-self-propagating-npm-worm-binding-gyp/)
- [IronWorm and New Miasma Worm Variant Hit npm in Supply Chain Attacks](https://thehackernews.com/2026/06/ironworm-and-new-miasma-worm-variant.html)
- [TeamPCP Supply Chain Campaign: Activity Through 2026-06-07](https://isc.sans.edu/diary/TeamPCP+Supply+Chain+Campaign+Activity+Through+20260607/33060/)
- [binding.gyp Supply Chain Attack Compromises Dozens of npm Packages Across Maintainer Accounts](https://cybersecuritynews.com/binding-gyp-supply-chain-attack-compromises-dozens-of-npm-packages/)
- [Supply Chain Attack Hits Dozens of npm Packages via binding.gyp](https://gbhackers.com/dozens-of-npm-packages-via-binding-gyp/)
- [npm v12 Ships This Month, Blocking Install Scripts That Enabled Year of Supply Chain Attacks](https://www.techtimes.com/articles/319890/20260708/npm-v12-ships-this-month-blocking-install-scripts-that-enabled-year-supply-chain-attacks.htm)
- [NPM 12 Will Change Script Execution Behavior to Prevent Supply Chain Attacks](https://www.securityweek.com/npm-12-will-change-script-execution-behavior-to-prevent-supply-chain-attacks/)
- [Miasma / TeamPCP npm Supply-Chain Attack](https://www.concretecms.com/about/blog/ai/miasma-teampcp-npm-supply-chain-attack)
- [npm Supply Chain Under Siege: TeamPCP, Miasma, and npm v12](https://labs.cloudsecurityalliance.org/research/csa-whitepaper-npm-ai-toolchain-supply-chain-security-v1-0-c/)
- [Active Exploitation Alert: Miasma Malware Campaign Targets npm Packages and GitHub Actions in Major Supply Chain Attack](https://www.rescana.com/post/active-exploitation-alert-miasma-malware-campaign-targets-npm-packages-and-github-actions-in-major-supply-chain-attack)
- [Red Hat npm Packages Compromised to Spread a Credential-Stealing Worm](https://www.aikido.dev/blog/red-hat-npm-packages-compromised-credential-stealing-worm)

## Full data

Detection queries (Splunk SPL / Microsoft KQL / Sigma) and IOC values require the Threadlinqs MCP server (Purple tier): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-1234
