12 min read
High
By

binding.gyp - an npm supply chain worm that abuses node-gyp instead of postinstall — and harvests CI/CD credentials

4 June 2026. StepSecurity reports an active, self-replicating npm worm that does not run via the usual preinstall/postinstall hooks but injects a binding.gyp file: npm then invokes node-gyp, and the attacker uses its shell expansion to execute code silently during npm install. The malware harvests credentials from npm, GitHub, AWS, GCP, Azure, HashiCorp Vault, Kubernetes and RubyGems, injects itself into GitHub Actions workflows and publishes poisoned versions of the victim’s other packages. Developing incident — the list of affected packages is growing.

TL;DR — 90 seconds

Affected?

npm packages across several maintainer accounts; so far dozens of poisoned versions in families like autotel-*, awaitly-*, executable-stories-* and node-env-resolver-* (plus single packages such as @vapi-ai/server-sdk, ai-sdk-ollama). All known malicious versions were published between 3 and 4 June 2026. The list is growing — the authoritative, continuously updated listing is at StepSecurity.

Risk?

Silent code execution during npm install via binding.gyp/node-gyp (without a postinstall hook), credential theft (npm/GitHub/AWS/GCP/Azure/Vault/Kubernetes/RubyGems), CI/CD worm propagation and workflow injection.

Immediate action?

Check builds/CI against the known package versions, search dependencies for suspicious binding.gyp, rotate affected credentials, check CI workflows for injected setup-bun steps.

Recommendation?

Mid-market and enterprise: freeze lockfiles, enforce --ignore-scripts in CI, minimise and short-live token scopes, audit recently updated npm dependencies.

Criticality?

high (references the hero badge — actively spreading worm, immediate audit within the 48h window).

What is the problem?

According to StepSecurity (developing incident, as of 3 June 2026), this worm deliberately does not run via the preinstall/postinstall lifecycle hooks in package.json — exactly the place security tools, reviewers and npm’s own audit systems look at. Instead, the attacker places a small binding.gyp file in the package. As soon as npm sees a binding.gyp, it automatically invokes node-gyp to compile a supposed native addon. The attacker abuses the shell expansion in the sources array:

 

{
  "targets": [
    {
      "target_name": "Setup",
      "type": "none",
      "sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]
    }
  ]
}

 

This silently runs node index.js during install. The scripts block of package.json contains only legitimate build commands; there is no postinstall hook to raise suspicion. According to StepSecurity the binding.gyp is only around 100 bytes — the index.js it triggers, however, is 4.5 to 4.9 MB of obfuscated code.

The malware runs in three stages according to StepSecurity. Stage 1 (obfuscated loader): the root index.js decodes an inner script via a ROT-N Caesar cipher, which then decrypts two AES-128-GCM-encrypted payloads using hardcoded keys. Stage 2 (runtime download): the first payload silently downloads the Bun JavaScript runtime (v1.3.13) from GitHub into a temporary directory — giving the attacker a fast, standalone runtime that leaves few traces in the Node.js process tree. Stage 3 (CI/CD worm): the second payload (~720 KB) is the actual worm and runs via the downloaded Bun runtime.

Who is affected?

AffectedNot affectedConditions / aggravating
Projects/CI pulling a poisoned version of a listed package (families autotel-*, awaitly-*, executable-stories-*/eslint-plugin-executable-stories-*, node-env-resolver-* and single packages such as @vapi-ai/server-sdk, ai-sdk-ollama, mountly, wrangler-deploy)Projects without one of the affected versions in the dependency tree (direct or transitive)npm install runs without --ignore-scripts; node-gyp available and triggered by the injected binding.gyp
Developer machines and CI pipelines with reachable cloud/registry credentialsPure runtime environments without an npm install step and without reachable secretsCredentials of npm, GitHub (incl. PATs), AWS (incl. IMDSv2/ECS task role), GCP, Azure (incl. Key Vault), HashiCorp Vault, Kubernetes, RubyGems in reach
Maintainer accounts whose tokens are stolen — their own packages get poisoned onwardStolen npm/RubyGems tokens allow publish; GitHub token allows workflow push

StepSecurity explicitly calls the incident „developing“ — the list of compromised packages and versions is continuously extended. The authoritative, current listing is in the source; we deliberately refrain from presenting a snapshot as complete.

Impact

The core is that code execution happens where the usual detections do not look: not in postinstall, but in the node-gyp build that npm itself triggers when a binding.gyp is present. With that, the attacker bypasses conventional tools according to StepSecurity.

The consequences StepSecurity documents are those of a full CI/CD worm. First, credential harvesting: the malware scans the environment for npm tokens, GitHub tokens and PATs, AWS access keys (including the IMDSv2 and ECS task role endpoints), GCP service account credentials, Azure client secrets and Key Vault contents, HashiCorp Vault tokens (across multiple file paths and the local Vault API), Kubernetes service account tokens, RubyGems API keys and passwords from 1Password CLI, gopass and pass; it also extracts masked secrets from the GitHub Actions runner process memory. Second, workflow injection: using stolen GitHub tokens, the worm modifies CI/CD workflow files in repos the victim can push to and inserts a setup-bun step plus a payload execution step — so it runs on every future CI job. Third, package poisoning: using stolen npm/RubyGems tokens it queries all packages the victim maintains, downloads them, injects the payload and publishes new poisoned versions — this is how the worm jumps from one account to dozens of packages. Fourth, exfiltration: the harvested credentials are encrypted with a hardcoded RSA public key and pushed as „dangling commits“ (commits not reachable from any branch) into attacker-controlled GitHub repos — hard to find through normal repo browsing.

There is no CVE number for this campaign; it is an ongoing supply chain incident, not a single product flaw. That is precisely why the operational severity is high: anyone pulling an affected version potentially loses the keys to their entire cloud and registry landscape.

Mitigation / immediate measures

Note: the following steps are our operational recommendation based on the documented technique — not a vendor-certified guide.

Operational Decision Block

Step 1 — harden installs

 

# Disable node-gyp/script execution on install globally (CI and local)
npm config set ignore-scripts true
# or per run:
npm ci --ignore-scripts

# Note: --ignore-scripts disables the automatic node-gyp execution that this
# binding.gyp technique exploits. Native modules then have to be built
# deliberately and in a controlled way.

 

Step 2 — audit the dependency tree

 

# Check whether an affected package family is in the tree (adjust/extend examples
# from the continuously updated StepSecurity list)
npm ls autotel autotel-mcp awaitly node-env-resolver executable-stories-vitest 2>/dev/null

# Search the lockfile for package names
grep -nE "autotel|awaitly|executable-stories|node-env-resolver|@vapi-ai/server-sdk|ai-sdk-ollama" package-lock.json

 

Step 3 — rotate credentials

 

If an affected version was installed (locally or in CI), treat as compromised:
- revoke and reissue npm, GitHub (incl. PATs) and RubyGems tokens
- rotate AWS/GCP/Azure keys, review Azure Key Vault
- rotate HashiCorp Vault and Kubernetes service account tokens
- assume password-manager CLI sessions (1Password/gopass/pass) are exposed

 

Step 4 — check CI workflows

 

# Check for injected setup-bun steps in workflows
grep -RInE "setup-bun|oven-sh/setup-bun" .github/workflows/

# Review unexpected workflow changes in git history
git log --oneline -- .github/workflows/

Detection / verification

IOCs derived directly from the technique documented by StepSecurity.

Find suspicious binding.gyp in dependencies

 

# List binding.gyp files in the node_modules tree
find node_modules -name binding.gyp

# Check for the characteristic shell expansion in the sources array
grep -RIn "<!(" node_modules --include=binding.gyp

# Suspicious: a very small binding.gyp (~100 bytes) next to a very large index.js (several MB)
find node_modules -name binding.gyp -size -200c

 

Bun runtime download and traces

 

According to StepSecurity, stage 2 downloads the Bun runtime (v1.3.13) from GitHub
into a temporary directory. Check points:
- unexpected Bun binaries in temp paths on dev machines / CI runners
- outbound connections to GitHub release assets during npm install
- in workflows: a setup-bun step that does not originate from your repo

 

Exfiltration pattern

 

Exfiltration happens, according to StepSecurity, as "dangling commits" into
attacker-controlled GitHub repos (not reachable from any branch).
- check for unusual, unreferenced commits in your own repos
- review the GitHub audit log for unexpected workflow/content pushes

Operator guidance

SMEs / Mittelstand

First contain, then rotate. Check lockfiles and CI caches against the affected package names; if a version is in there, treat all tokens reachable from the pipeline as compromised and rotate them. Enforce --ignore-scripts in CI — it disables the automatic node-gyp execution this technique exploits. Build native modules deliberately and in a controlled way afterwards.

Enterprise

Additionally: short-lived, tightly scoped CI credentials (OIDC instead of long-lived keys), egress control on build runners, and an audit that correlates recently updated npm dependencies with workflow changes. The workflow injection is the most dangerous part here — a setup-bun step injected once persists across future CI runs.

Kubernetes / containers

Rebuild build images once an affected version was in the tree; old layers carry the poisoned version onward. Rotate service account tokens, keep IMDS access on build pods restrictive (the malware explicitly targets IMDSv2/ECS task role).

Declarative stacks (NixOS / Talos / Flatcar)

Pin to known-good versions, reproducible rebuild, and the advantage of the declarative track: which npm version flowed into which build and when is provable — exactly what speeds up containing a supply chain incident.

What we did concretely

We treat supply chain worms as a pipeline-discipline question, not a single package. For the stacks we operate this means: --ignore-scripts is the default in CI, native builds run in a controlled way and not incidentally during install; CI credentials are short-lived and tightly scoped; egress on build runners is restricted. As a response to this incident we checked lockfiles and caches against the package families listed by StepSecurity and ran a sweep for binding.gyp files with the characteristic <!( shell expansion.

The lesson from this incident is not „yet another npm worm“ but the shift of the execution point: anyone who pins detection and policy only to preinstall/postinstall does not see a binding.gyp-triggered node-gyp execution. This fits the pattern we described with Shai-Hulud (@antv) and the Miasma/@redhat-cloud-services wave — only that the trigger mechanism is new here. That is why for us: install scripts (including implicit node-gyp builds) are off by default in CI, and token reach is kept as small as possible so that a single compromised install does not open the whole cloud landscape.

Frequently asked questions about the binding.gyp npm worm

Does npm install --ignore-scripts protect against the binding.gyp technique?+

Yes, in practice: the attack uses the automatic node-gyp execution that npm triggers when a binding.gyp is present. --ignore-scripts disables this install execution. Native modules then have to be built deliberately and in a controlled way — that is the price, and it is worth it.

Why do classic postinstall scanners not catch this?+

Because there is no postinstall hook. The scripts block of package.json contains only legitimate build commands; code execution runs via the 100-byte binding.gyp and node-gyp’s shell expansion in the sources array. Tools that only check lifecycle hooks do not see it, according to StepSecurity.

Which packages are affected?+

So far dozens of versions in families like autotel-*, awaitly-*, executable-stories-* and node-env-resolver-* as well as single packages such as @vapi-ai/server-sdk and ai-sdk-ollama, all published between 3 and 4 June 2026. It is a developing incident — the authoritative, current list is at StepSecurity, not here.

Which credentials are at risk if a build was affected?+

According to StepSecurity: npm, GitHub (incl. PATs), RubyGems tokens, AWS keys (incl. IMDSv2/ECS task role), GCP, Azure (incl. Key Vault) credentials, HashiCorp Vault and Kubernetes tokens, and passwords from 1Password CLI/gopass/pass. Additionally, masked secrets are extracted from the GitHub Actions runner memory. In the worst case: rotate everything the pipeline could reach.

How do I tell whether the worm has nested in our CI?+

Check your workflow files for a setup-bun step that does not originate from you (grep -RIn "setup-bun" .github/workflows/) and the git history of the workflows for unexpected changes. According to StepSecurity, the worm injects exactly this step so it runs on every future CI job.

Is there a CVE number or a patch?+

No. This is an ongoing supply chain campaign, not a single product flaw — accordingly there is no CVE and no vendor patch. The „fix“ is operational: avoid affected versions, harden installs, rotate exposed credentials, clean up CI workflows.

Conclusion

This worm is technically no more spectacular than the npm waves before it, but it hits a blind spot: code execution moves from postinstall into the node-gyp build that npm itself triggers on a binding.gyp. Anyone who pins policy and detection only to lifecycle hooks does not see it. The effective answer is unspectacular and well known: install scripts off by default in CI (--ignore-scripts), native builds deliberate and controlled, credentials short-lived and tightly scoped, workflow changes monitored. Because the incident is ongoing, the source governs the package list, not a snapshot. Do not dramatise, but check today — the reach of a single compromised install here extends into the entire cloud and registry landscape.

Sources

Before the next install harvests your CI secrets — let’s talk about your pipeline discipline.

We check, mitigate and validate your npm/CI supply chain against worms like the binding.gyp incident.

Dependency and lockfile audit against the affected package families, --ignore-scripts enforcement in CI, token scoping and rotation, workflow integrity checks and egress control on build runners.

Platform operations instead of advice-on-paper: we check, mitigate and validate production pipelines — from the SBOM inventory through the stopgap measure to validation.

Book an appointment directly

About the author

[Translate to English:] Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Founder · Moselwal Digitalagentur · OnlyOle

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012, now Moselwal. Over 100 projects, with a focus on security, performance, automation and quality.