By falco365 · Published April 23, 2026

CVE-2026-12091: npm postinstall supply-chain hijack via maintainer-account takeover

Five widely-installed npm packages (combined 38M weekly downloads) published compromised versions after maintainer 2FA bypass. Postinstall hooks exfiltrated env vars, SSH keys, and git credentials. Runs at every npm install. CVSS 8.8.

CVE-2026-12091: npm postinstall supply-chain hijack via maintainer-account takeover
Analysis

CVE-2026-12091 covers a set of compromised npm package versions published over a 48-hour window in April after an attacker bypassed 2FA on five maintainer accounts via session-token replay from a phishing campaign. The malicious versions each ship a postinstall script that exfiltrates the host's environment variables, SSH private keys, .netrc, git config, and npm auth tokens to a Cloudflare-fronted C2 endpoint. Every npm install, npm ci, yarn install, or pnpm install that resolved to an affected version during that window ran the hook. Combined affected weekly-download count: 38M.

Why postinstall is the worst place to land

Developer environments are the highest-trust environments most organizations own. The CI runner that builds your app has every credential needed to deploy. The engineer's laptop has SSH access to production-adjacent systems, git tokens that can force-push to main, and cloud CLI configs that often include long-lived access keys. A postinstall hook that runs during routine dependency updates inherits all of that, quietly.

The exploit window:

  • April 14, 02:17 UTC — attacker publishes compromised versions of five packages (names withheld pending npm registry review; IOC list in the artifact folder).
  • April 15, ~19:00 UTC — first telemetry of the postinstall C2 traffic from EDR vendors.
  • April 16, 03:40 UTC — npm security team unpublishes the malicious versions and resets maintainer credentials. Clean versions re-published same day.
  • April 18 — CVE assigned, GHSA published, IOC list finalized.
If your CI ran npm install (without a lockfile pinning to a clean version) between April 14 and April 16, assume the CI host's short-lived tokens leaked. Rotate them today.
Who is exposed
  • CI/CD runners that ran npm install or npm ci --registry=https://registry.npmjs.org in the 48-hour window without a lockfile pinning a clean version. GitHub Actions self-hosted and hosted runners both in scope.
  • Developer laptops that ran npm install or npm update against affected package ranges — SSH keys, git tokens, cloud credentials all potentially exfiltrated.
  • Docker build environments where the npm install step ran with build-time secrets (common anti-pattern in Dockerfiles).
  • Not in scope: teams using --ignore-scripts or a registry proxy with script-execution disabled. If you've been paranoid about postinstall hooks for years, you benefited.
Mitigation
  • Check the IOC list (in the artifact folder and linked from the GHSA) against your package-lock.json / yarn.lock / pnpm-lock.yaml. If any pinned version matches a compromised version, assume host compromise for any environment that resolved it.
  • Rotate every credential that was reachable from the affected host: npm tokens, git PATs, cloud keys, SSH keys, long-lived tokens in .env files.
  • Move to npm ci --ignore-scripts in CI as a defense-in-depth default. Most packages don't need postinstall; the ones that do are documented and can be scripts-allowed via allowlist.
  • Enforce provenance (npm publish --provenance) and configure your CI to reject packages without provenance attestations for critical dependencies.
  • 2FA + phishing-resistant factors (WebAuthn, not TOTP) on maintainer accounts for any package you publish.
The broader pattern

npm postinstall-based attacks are now a quarterly event. ua-parser-js (2021), colors / faker (2022), node-ipc / peacenotwar (2022), event-stream (2018), and now CVE-2026-12091. Each one has the same shape: compromised maintainer account, malicious version published, postinstall hook steals credentials. The ecosystem response has been incremental (provenance, 2FA requirements, automated scanning). The practitioner response should be structural: --ignore-scripts by default, allowlist scripts that genuinely need to run, and treat any postinstall in a dependency as a code-review item — not a yellow line in the output of npm install.

This CVE belongs to the small subset of disclosures that the criminal market repackages within days, not months — the implant is the postinstall script itself, no exploit-development work required. The CopyFail time-to-criminalization analysis frames this as a "first-bucket" pattern: bugs where the work is already done get incorporated into commodity stealer infrastructure on the order of days. Patch and rotate on that timeline rather than the standard CVE cadence.

The pattern is also live in 2026 in larger forms. Team PCP's six-week chain through security tooling vendors exploits the same install-time-execution surface across npm, PyPI, GitHub Actions, and Docker Hub — and the Mini Shai-Hulud cluster of April 29-30 uses it with a Bun-runtime evasion layer. Treat CVE-2026-12091's mitigations as the structural answer to all of these: lockfile pinning, --ignore-scripts by default, sandboxed install boundaries, capability-narrowed CI tokens.