Shai-Hulud: Self‑Spreading npm Backdoor Hits tinycolor and 40+ Packages

Read Articleadded Sep 16, 2025
Shai-Hulud: Self‑Spreading npm Backdoor Hits tinycolor and 40+ Packages

The @ctrl/tinycolor package and 40+ npm packages were compromised in a self-propagating attack (“Shai-Hulud”) that harvests credentials, injects a GitHub Actions backdoor, and exfiltrates data via webhooks and public GitHub repos. The payload runs during npm install, targets Linux/macOS, and uses maintainer credentials to spread by force-publishing patched releases. The article lists IoCs, affected versions, and step-by-step remediation: remove compromised packages, purge malicious workflows/branches, rotate all credentials, audit cloud access, and harden CI/CD.

Key Points

  • Malware bundled as bundle.js runs on npm install to harvest credentials (env vars, filesystem via TruffleHog, AWS/GCP secret managers) and targets Linux/macOS.
  • Self-propagation abuses NPM tokens to identify a maintainer’s packages and force-publish patched releases, creating a cascading compromise across the ecosystem.
  • Persistence is established by injecting a GitHub Actions workflow (shai-hulud-workflow.yml) that exfiltrates secrets and manipulates Git references via the GitHub API.
  • Exfiltration leverages both a webhook endpoint and creation of public GitHub repos named “Shai-Hulud,” echoing patterns from prior supply-chain incidents.
  • Immediate response requires removing affected versions, deleting malicious workflows/branches, rotating all credentials, auditing cloud logs, and hardening CI/CD and GitHub security.

Sentiment

Concerned and critical of npm’s security posture but broadly constructive; most agree the attack is serious and push for practical mitigations (pinning, cooldowns, provenance, sandboxing), with debate over feasibility and responsibility across ecosystems.

In Agreement

  • Npm’s current model (permissive postinstall, widespread tokens, rapid unsupervised publishing) creates a large attack surface; registries should enforce stronger controls (2FA, OIDC/trusted publishing, provenance/attestations, cooldowns).
  • Pinning/locking dependencies, delaying upgrades (minimum age), and minimizing transitive deps reduce exposure and blast radius.
  • Disable postinstall scripts by default or require allow‑listing; most packages don’t legitimately need them.
  • Run installs/builds in sandboxed, hermetic CI with reproducible builds; separate build from publish credentials and enforce least privilege.
  • Use internal mirrors/pull‑through caches and curated allowlists (Debian‑style gating) to add a review/audit layer before consumption.
  • Adopt capability‑based permissions (Deno‑style) and richer standard libraries or consolidated utility suites to avoid micro‑deps.
  • Leverage ecosystem safeguards: immutable versions, automated yanking, transparency logs, checksums, cargo vet‑style audits.

Opposed

  • This isn’t uniquely an npm/JS problem; similar risks exist in PyPI, crates.io, Maven, Go modules—focusing fixes on npm alone is shortsighted.
  • Rewriting or vendoring everything is impractical; reduction in deps can backfire if it forces large maintenance burdens or stale/insecure code.
  • Delaying updates can hinder timely patching and may not improve detection if few people install during the delay window.
  • 2FA, signatures, and provenance help but don’t stop malicious maintainers (rug‑pulls) or compromised repos/workflows; trust store management is hard.
  • Lockfiles already prevent surprise upgrades in many setups; claims that npm install always pulls newer versions are overstated or outdated.
  • Heavy curation (Debian‑style) won’t scale to millions of packages; auditing every new version is infeasible without major funding.
  • Removing postinstall alone isn’t sufficient since malicious code can execute on import/run; broader sandboxing and permissioning are needed.
Shai-Hulud: Self‑Spreading npm Backdoor Hits tinycolor and 40+ Packages