Postmortem: TanStack NPM supply-chain compromise

Attack and root cause

  • Worm (“Mini Shai-Hulud”) compromised legitimate npm packages by:
    • Exploiting GitHub Actions via pull_request_target plus cache poisoning.
    • Writing a malicious pnpm store into the shared Actions cache from a fork PR.
    • Having the main/release workflow later restore that poisoned cache and publish malicious tarballs with valid SLSA provenance.
  • Payload steals GitHub tokens and installs a “dead-man’s switch” user service / LaunchAgent that rm -rf ~ if the stolen token is revoked.
  • Attack also hit other popular npm packages and is spreading downstream; impact is still evolving.

GitHub Actions & Trusted Publishing concerns

  • pull_request_target is widely criticized as a “landmine”; docs warn against running untrusted code with it, but it remains easy to misuse.
  • Core design issue: Actions cache scope is per-repo and shared between untrusted PR runs and protected main/release runs.
  • Permissions model is confusing; workflows that appear “read-only” can still write caches.
  • Trusted Publishing removes long‑lived registry tokens but doesn’t add a second factor; if CI or a repo admin token is compromised, an attacker can still publish.
  • Some argue additional gates (environments, manual approvals) help; others note admin tokens can often bypass those via API.

Defenses and mitigations discussed

  • Common recommendations:
    • Enable minimum release age / cooldowns in npm, pnpm, bun, yarn, uv, pip.
    • Commit lockfiles, use npm ci / pnpm --frozen-lockfile, and pin exact versions.
    • Disable or tightly control lifecycle scripts (ignore-scripts, pnpm/bun defaults, allow-git=none).
    • Separate caches for PR vs release; or forbid untrusted workflows from writing cache.
    • Add static analysis for Actions (e.g., tools that detect pull_request_target + checkout patterns).
  • Some advocate publishing from isolated pipelines or separate projects, and using VMs or stronger sandboxing for dev environments.

Ecosystem and dependency culture debate

  • Many see npm/JS as uniquely bad: massive transitive dependency graphs, lifecycle scripts by default, frequent supply‑chain incidents.
  • Others argue any ecosystem with unaudited third‑party packages is vulnerable; npm is just the biggest target.
  • Discussion of alternatives: Go modules, Cargo, Java/Maven, Python, distro packaging, larger standard libraries, or “just write the code yourself.”

Broader reflections

  • Tension between “audit dependencies” vs cost and complexity; some now pay for AI audits or avoid upgrades entirely.
  • Frustration that registry unpublish rules and slow security response leave malicious versions installable for hours.
  • Growing sentiment that current CI/package manager defaults are unsafe and need stronger, opinionated security-by-default.