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

5.9 KiB

GH Actions - npm Supply Chain Abuse

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

Overview

Nachdem ein Angreifer Code Execution in einem GitHub Actions release workflow, auf einer Maintainer-Workstation oder in einer Package Build Pipeline erlangt hat, wird npm publishing zu einem hochwirksamen Pivot. Das Ziel ist normalerweise, Publisher-Identitätsmaterial zu stehlen, bösartige Versionen zu veröffentlichen und nachgelagerte installs in weitere credential-generation nodes zu verwandeln.

Typische credential sources:

  • ~/.npmrc, NPM_TOKEN, registry sessions und npm automation tokens.
  • GitHub PATs, GITHUB_TOKEN, release-bot credentials, SSH keys und .netrc / git credential helpers.
  • GitHub Actions OIDC request material (ACTIONS_ID_TOKEN_REQUEST_URL und ACTIONS_ID_TOKEN_REQUEST_TOKEN) in Jobs mit id-token: write.
  • Cloud credentials, Vault tokens, Kubernetes service account tokens und .env files, die in der release environment vorhanden sind.

Install-Time Execution Primitives

Lifecycle hooks

Der klassische npm-Weg ist, eine bösartige package version mit preinstall, install, postinstall oder prepare scripts zu veröffentlichen. Jede developer workstation oder jeder CI job, der die Version installiert, führt vom Angreifer kontrollierten code aus.

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

Defenders überwachen diese Skripte oft, daher sollten red-team Reviews auch weniger offensichtliche Execution Paths prüfen.

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

Nicht jeder Execution Path zur Installationszeit liegt in package.json Lifecycle Hooks. Der configure-Schritt von node-gyp sucht im Paketverzeichnis nach einer binding.gyp-Datei, sodass ein kompromittierter Publisher die Ausführung in den nativen Build-Pfad verlagern und Kontrollen umgehen kann, die nur preinstall / postinstall prüfen.

Praktische Checks:

  • Prüfe das veröffentlichte tarball, nicht nur das Git Repo, auf unerwartete binding.gyp, node-gyp oder native-addon Metadaten in Paketen, die eigentlich reines JavaScript sein sollten.
  • Behandle eine plötzliche binding.gyp-Ergänzung als execution primitive, besonders wenn Defenders auf Lifecycle-Hook-Monitoring oder --ignore-scripts setzen.
  • Review Release-Jobs, die npm install, npm rebuild oder dependency build steps nach dem Wiederherstellen untrusted Artifacts/Caches ausführen.

Wormable npm Publishing

Sobald Code auf einem Maintainer-Workstation oder in einem Release-Workflow läuft, kann eine einzige gestohlene Registry Identity in eine sich selbst verbreitende Package-Kompromittierung umgewandelt werden:

  1. Sammle Maintainer-Secrets (~/.npmrc, PATs, OIDC request env vars, cloud creds, SSH keys).
  2. Ermittle Packages, für die die kompromittierte Identity oder das Team publishen kann.
  3. Veröffentliche bösartige Versionen erneut über jedes schreibbare Package.
  4. Lasse nachgelagerte Installationen weitere credential-generation nodes erzeugen.

Nützliche Enumeration aus einer kompromittierten npm Identity:

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

Angreifer bevorzugen normalerweise Packages mit häufigen CI-Installationen, transitive popularity oder Release-Automation, die die bösartige Version schnell installiert.

Trusted Publishing and Provenance Limits

Trusted publishing/OIDC entfernt langlebige statische npm-Tokens, macht aber einen kompromittierten Release-Workflow nicht sicher. Wenn der Angreifer Code kontrolliert, der in einem Job mit id-token: write ausgeführt wird, kann der bösartige Release trotzdem gültige provenance erhalten, weil der legitime Workflow ihn tatsächlich gebaut und veröffentlicht hat.

Provenance beantwortet welcher Workflow dieses Artifact gebaut hat, nicht ob der Workflow, der Source Tree, der Cache oder die Build-Schritte sauber waren.

High-signal Review-Punkte:

  • Workflows, die id-token: write mit npm publish, pnpm publish, changesets, Release-Bots oder custom publish wrappers kombinieren.
  • Release-Jobs, die Caches oder Artifacts aus lower-trust Workflows wiederherstellen, bevor sie veröffentlichen.
  • Jobs, die ohne menschliche Genehmigung, environment protection rules oder einen zweiten Reviewer veröffentlichen.
  • Workflows, die OIDC anfordern, bevor alle Build-Inputs verifiziert wurden.

Hardening

  • Verwende trusted publishing/OIDC statt statischer npm-Tokens, aber kombiniere es mit protected environments und menschlicher Genehmigung für sensitive Scopes.
  • Füge staged publishing / menschliche 2FA-Genehmigung für Packages mit hohem Impact hinzu, wo möglich.
  • Verwende minimumReleaseAge oder vergleichbare dependency quarantine controls, bevor du neu veröffentlichte Package-Versionen konsumierst.
  • Trenne Cache-Keys nach trust boundary und führe wiederhergestellte Cache-Inhalte niemals vor Integritätsprüfungen aus.
  • Vergleiche veröffentlichte Tarballs mit Source Repositories und alarmiere bei unerwarteten nativen Build-Metadaten wie binding.gyp.
  • Deaktiviere oder prüfe Lifecycle-Skripte in CI (npm config set ignore-scripts true) sehr genau, wenn Builds sie nicht brauchen.
  • Überwache Package-Zugriff (npm access ls-packages) und entferne veraltete Maintainer, Bots und Teams.

References

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