docs/security/supply-chain-incident-response.md
This playbook is the ECC operator runbook for npm, GitHub Actions, and cross-ecosystem package-registry incidents. It is intentionally conservative: registry signatures, provenance, and trusted publishing are useful signals, but they do not prove that the workflow executed the intended code path.
As of 2026-05-15, the active incident class is the May 2026 TanStack npm supply-chain compromise and broader Mini Shai-Hulud campaign. ECC keeps the same IOC sweep for the related npm/PyPI waves because these incidents target package install/publish paths, AI developer-tool configs, and developer credentials:
@tanstack/* packages,
published on 2026-05-11 between 19:20 and 19:26 UTC.GHSA-g7cv-rxg3-hmpx / CVE-2026-45321 describes
install-time malware that harvests cloud credentials, GitHub tokens, npm
credentials, Vault tokens, Kubernetes tokens, and SSH private keys.node-ipc report describes a separate active npm
compromise affecting node-ipc versions 9.1.6, 9.2.3, and 12.0.1,
with historical malicious node-ipc versions also blocked by ECC because
they carried destructive or unauthorized file-writing behavior..claude/settings.json, VS Code .vscode/tasks.json, Zed
.zed/tasks.json, and OS-level gh-token-monitor LaunchAgent/systemd
services. Some variants add
~/.config/gh-token-monitor/token plus a dead-man-switch token description
IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner, malicious workflow
files such as .github/workflows/codeql_analysis.yml, and Python runtime
payloads such as transformers.pyz / pgmonitor.py. Remove those
persistence hooks before rotating a stolen GitHub token.router_init.js
SHA-256 prefix/suffix ab4fcada...8601266c, tanstack_runner.js
SHA-256 prefix/suffix 2ec78d55...6be27fc96,
opensearch_init.js, vite_setup.mjs, campaign salt svksjrhjkcejg,
Session protocol strings, [email protected] dead-drop
commits, dependabout/ branch names, and OhNoWhatsGoingOnWithGitHub.node-ipc sweep watches for node-ipc.cjs payload hash
96097e06...d9034144, tarball hashes for the malicious 9.1.6, 9.2.3,
and 12.0.1 artifacts, sh.azurestaticprovider.net, bt.node.js,
37.16.75.69, DNS exfil labels xh / xd / xf where present in
artifacts, __ntw, __ntRun, /nt- temp archives, and archive entries such
as uname.txt, envs.txt, and fixtures/_paths.txt.pull_request_target, GitHub Actions cache
poisoning across a fork/base trust boundary, and OIDC token extraction from a
GitHub Actions runner.Primary references:
Run this before a release candidate, after a broad dependency bump, and after any package-registry incident.
npm run security:ioc-scan
node scripts/ci/scan-supply-chain-iocs.js --home
npm ci --ignore-scripts
npm audit signatures
npm audit --audit-level=high
node scripts/ci/supply-chain-advisory-sources.js --json
node scripts/ci/validate-workflow-security.js
node tests/scripts/npm-publish-surface.test.js
node tests/run-all.js
If a search hit appears only in documentation examples, note it in the release evidence but do not rotate credentials for a docs-only reference.
ECC also runs .github/workflows/supply-chain-watch.yml every six hours and on
manual dispatch. The workflow is read-only, disables checkout credential
persistence, installs with npm ci --ignore-scripts, verifies npm registry
signatures, runs the IOC scanner fixtures, runs
scripts/ci/supply-chain-advisory-sources.js --refresh --json, emits
supply-chain-ioc-report.json and supply-chain-advisory-sources.json, and
re-validates GitHub Actions hardening rules.
Treat a failed scheduled watch as a release blocker until an operator confirms
whether the failure is a newly reported advisory, a stale scanner fixture, a
registry-signature issue, or a workflow hardening regression. If the scanner
needs new indicators, update scripts/ci/scan-supply-chain-iocs.js, add fixture
coverage in tests/ci/scan-supply-chain-iocs.test.js, refresh this runbook, and
attach the latest JSON artifact to the release evidence.
The advisory-source artifact is the ITO-57 status payload. It records the
trusted source registry, live URL refresh warnings, and a Linear-ready summary.
Refresh source coverage through npm run security:advisory-sources -- --json
before changing IOC coverage, and attach the artifact to the next Linear project
status update after each significant merge batch.
If ECC or a maintainer machine installed a known-bad package version:
package-lock.json, pnpm-lock.yaml, or yarn.lock;~/.claude/settings.json SessionStart hooks and adjacent
router_runtime.js / setup.mjs payload files;.vscode/tasks.json folder-open tasks and adjacent payload files;~/Library/LaunchAgents/com.user.gh-token-monitor.plist;~/.config/systemd/user/gh-token-monitor.service;~/.config/systemd/user/pgsql-monitor.service;~/.config/gh-token-monitor/token;~/.local/bin/gh-token-monitor.sh;~/.local/bin/pgmonitor.py;/tmp/transformers.pyz, /tmp/pgmonitor.py, and their
/private/tmp/ equivalents on macOS..npmrc tokens;npm ci --ignore-scripts, pnpm install --ignore-scripts,
yarn install --mode=skip-build, or bun install --ignore-scripts.ECC enforces these rules through scripts/ci/validate-workflow-security.js:
id-token: write must not restore or save shared dependency
caches;npm audit must also run npm audit signatures;pull_request_target workflows must not restore or save shared dependency
caches.Treat any violation as a release blocker.
Before tagging or publishing ECC:
id-token: write limited to release workflows that do not use shared
dependency caches.Escalate to a maintainer security review before any release or merge if:
node scripts/ci/scan-supply-chain-iocs.js --home finds Claude Code,
VS Code, Zed, or OS-level persistence indicators;pull_request_target with dependency installation,
cache restore/save, PR-head checkout, or write permissions;id-token: write with shared cache usage;