Files
hacktricks-cloud/src/pentesting-ci-cd/github-security/abusing-github-actions/gh-actions-npm-supply-chain-abuse.md
T

5.3 KiB

GH Actions - npm Supply Chain Abuse

{{#include ../../../banners/hacktricks-training.md}}

Overview

Após um atacante obter code execution em um GitHub Actions release workflow, maintainer workstation ou package build pipeline, publicar no npm se torna um pivot de alto impacto. O objetivo geralmente é roubar material de identidade do publisher, publicar versões maliciosas e transformar downstream installs em mais nós de geração de credentials.

Fontes típicas de credentials:

  • ~/.npmrc, NPM_TOKEN, registry sessions e npm automation tokens.
  • GitHub PATs, GITHUB_TOKEN, release-bot credentials, SSH keys e .netrc / git credential helpers.
  • Material de solicitação OIDC do GitHub Actions (ACTIONS_ID_TOKEN_REQUEST_URL e ACTIONS_ID_TOKEN_REQUEST_TOKEN) em jobs com id-token: write.
  • Cloud credentials, Vault tokens, Kubernetes service account tokens e arquivos .env presentes no release environment.

Install-Time Execution Primitives

Lifecycle hooks

A rota clássica do npm é publicar uma versão maliciosa de package com scripts preinstall, install, postinstall ou prepare. Qualquer developer workstation ou job de CI que instala a versão executa code controlado pelo atacante.

{
"scripts": {
"postinstall": "node ./scripts/collect.js"
}
}

Defenders often monitor these scripts, so red-team reviews should also inspect less obvious execution paths.

binding.gyp / node-gyp execution (Phantom Gyp)

Not every install-time execution path lives in package.json lifecycle hooks. node-gyp's configure step looks for a binding.gyp file in the package directory, so a compromised publisher can shift execution into the native build path and bypass controls that only audit preinstall / postinstall.

Practical checks:

  • Inspect the published tarball, not only the Git repo, for unexpected binding.gyp, node-gyp, or native-addon metadata in packages that should be pure JavaScript.
  • Treat a sudden binding.gyp addition as an execution primitive, especially if defenders rely on lifecycle-hook monitoring or --ignore-scripts.
  • Review release jobs that run npm install, npm rebuild, or dependency build steps after restoring untrusted artifacts/caches.

Wormable npm Publishing

Once code runs in a maintainer workstation or release workflow, a single stolen registry identity can be turned into self-propagating package compromise:

  1. Harvest maintainer secrets (~/.npmrc, PATs, OIDC request env vars, cloud creds, SSH keys).
  2. Enumerate packages the compromised identity or team can publish to.
  3. Republish malicious versions across each writable package.
  4. Let downstream installs create more credential-generation nodes.

Useful enumeration from a compromised npm identity:

npm whoami
npm access ls-packages
npm access ls-collaborators <scope-or-package>

Attackers usually prefer packages with frequent CI installs, transitive popularity, or release automation that will install the malicious version quickly.

Trusted Publishing and Provenance Limits

Trusted publishing/OIDC removes long-lived static npm tokens, but it does not make a compromised release workflow safe. If the attacker controls code that runs in a job with id-token: write, the malicious release can still receive valid provenance because the legitimate workflow really built and published it.

Provenance answers which workflow built this artifact, not whether the workflow, source tree, cache, or build steps were clean.

High-signal review points:

  • Workflows combining id-token: write with npm publish, pnpm publish, changesets, release bots, or custom publish wrappers.
  • Release jobs that restore caches or artifacts from lower-trust workflows before publishing.
  • Jobs that publish without human approval, environment protection rules, or a second reviewer.
  • Workflows that request OIDC before all build inputs have been verified.

Hardening

  • Use trusted publishing/OIDC instead of static npm tokens, but pair it with protected environments and human approval for sensitive scopes.
  • Add staged publishing / human 2FA approval for high-impact packages where possible.
  • Use minimumReleaseAge or equivalent dependency quarantine controls before consuming newly published package versions.
  • Separate cache keys by trust boundary and never execute restored cache contents before integrity checks.
  • Diff published tarballs against source repositories, and alert on unexpected native build metadata such as binding.gyp.
  • Disable or tightly review lifecycle scripts in CI (npm config set ignore-scripts true) where builds do not need them.
  • Monitor package access (npm access ls-packages) and remove stale maintainers, bots, and teams.

References

{{#include ../../../banners/hacktricks-training.md}}