When a popular open source package is poisoned, every organisation that installed it inherits an incident it did not cause and usually learns about from a social media post. This guide is for the consumer side: the security, platform and engineering teams who need to decide within hours whether they were exposed, what the malware could have taken, and which machine credentials to revoke. It draws on the Shai-Hulud, ChainDrop, Nx s1ngularity and tj-actions cases in the NHI Mgmt Group breach database and on CISA and GitHub guidance. Maintainer-side hardening and full response playbooks are covered in linked guides; this page is the decision path in the first 72 hours and the controls that shrink the next one.
Key takeaways
- The payload is a credential stealer. Recent npm and PyPI compromises read CI secrets, cloud keys, GitHub and npm tokens and AI tool credentials, so the response is mostly an NHI revocation exercise.
- CI runners are the main victims. In the second Shai-Hulud wave, Wiz attributed 77% of infections to CI/CD runners and 23% to developer machines, as reported on the breach page.
- Clean before you revoke when the malware watches its token. Microsoft reported that ChainDrop carried a destructive handler that fires when a monitored token is revoked.
- Lockfiles answer "were we exposed" in minutes. Without lockfiles and build logs you cannot prove a negative and must assume compromise.
- Provenance is not innocence. ChainDrop versions were published through a real trusted-publishing workflow with valid Sigstore provenance, so signature checks alone would have passed them.
What the breach data shows
NHI Mgmt Group, The State of NHI & AI Agent Breach Report 2026 (October 2026), found that supply chain is now the number one known way in: 51 of the 200+ breaches analysed came through a poisoned package, build tool or CI pipeline, and supply chain attacks made up 38% of 2026 breaches. The most common combination in the whole dataset was supply chain with a CI/CD or publishing token (34 breaches), followed by supply chain with a secret or password (25) and supply chain with a source control token (24). The report records Shai-Hulud spreading through stolen publishing tokens to about 800 npm packages and ChainDrop spreading a stealer to 444 npm packages from one maintainer account.
For a consumer, the lesson is that a malicious version is rarely the end goal. It is the delivery mechanism for stealing the machine credentials on your build hosts, which are then used to publish more poisoned packages or to reach your cloud.
How recent compromises behaved
| Case | Execution point | What it took | Consumer-relevant detail |
|---|---|---|---|
| Shai-Hulud npm Worm 2025 (second wave, 24 November 2025) | preinstall script installing Bun and running a payload | GitHub and npm tokens, AWS, GCP and Azure credentials, cloud secret stores | Persistence via a discussion.yaml workflow and a self-hosted runner named SHA1HULUD; Wiz reported over 60% of leaked npm tokens still valid a week later |
| ChainDrop npm Worm 2026 (4 August 2026) | preinstall running setup.mjs | npm, GitHub, cloud, Kubernetes, Vault, SSH and AI coding tool credentials; Runner.Worker memory | Persistence in .vscode/tasks.json and a SessionStart hook in .claude/settings.json; destructive handler on token revocation |
| Nx s1ngularity Attack 2025 (26 August 2025) | Post-install script | GitHub and npm tokens, SSH keys, cloud credentials, AI tool configuration; GitGuardian found 2,349 distinct secrets | Prompted local AI CLIs with permission-bypass flags to search for files; malicious versions live for about four to five hours |
| tj-actions/changed-files Compromise 2025 (CVE-2025-30066) | Moved release tags in a GitHub Action | Every secret in the runner, printed double base64-encoded to build logs | CISA exposure window 12 March 00:00 UTC to 15 March 12:00 UTC; public repository logs were readable by anyone |
The pattern repeats across ecosystems. For the worm family in depth, see the Shai-Hulud npm Worm Guide; for typosquats and dependency confusion, which call for a different triage, see the Malicious Package and Dependency Confusion Guide.
The first 72 hours
Hours 0 to 4: establish exposure
- Get the indicator set. Collect affected package names, versions and the exposure window from the advisory or the reporting researcher. Record the source and time, because version lists change during a campaign.
- Search lockfiles, including nested dependencies. CISA's Shai-Hulud alert told organisations to check
package-lock.jsonoryarn.lockfor affected packages, including nested dependencies, and to search artefact repositories and dependency tools for cached copies. - Search build logs for the window. A lockfile shows what a project would install; CI logs show what actually ran and when. For a compromised GitHub Action, find every workflow run that used it inside the window.
- Block the bad versions. Remove them from internal registries and caches, add deny rules in your proxy, and pin to a known-good version. CISA advised pinning to releases from before the compromise date.
Hours 4 to 24: contain the hosts
- Treat every host that installed the version as compromised. That includes ephemeral CI runners (their secrets were real even if the VM is gone), self-hosted runners and developer laptops. Microsoft's ChainDrop guidance applies this to any workstation or runner that installed an affected version with lifecycle scripts enabled.
- Remove persistence before revoking where the family is known to retaliate. Check for unknown workflows, self-hosted runners,
.vscode/tasks.jsonentries and AI tool hooks, then rebuild or reimage. Then revoke. - Isolate self-hosted runners and pause release jobs so a stolen publishing token cannot push from your own pipeline.
Hours 24 to 72: revoke, hunt and recover
- Revoke every credential the host could reach (next section), highest privilege first: publishing tokens, cloud admin and CI organisation secrets.
- Hunt for use of stolen credentials. Look for new public repositories in your GitHub organisation (for example named "Sha1-Hulud: The Second Coming" or "s1ngularity-repository"), unexpected package versions published under your names, private repositories made public, new cloud access keys and unusual secret store reads.
- Delete exposed logs. GitHub's guidance is that if an unredacted secret appears in a run log, delete the log and rotate the secret.
- Rebuild from clean. Rebuild artefacts produced during the window with a pinned, known-good dependency set and redeploy.
A fuller role-based playbook with communication and evidence steps is in the Malicious Open Source Package Response Playbook and, for self-spreading families, the Malicious Package Worm Response Playbook.
Which credentials to revoke
| Where the package ran | Credentials in reach | Revocation priority |
|---|---|---|
| GitHub Actions or other CI runner | All secrets exposed to the job (memory scraping reads secrets not referenced by the step), GITHUB_TOKEN, OIDC tokens issued in the job, publishing tokens, cloud keys | Highest: publishing and cloud credentials, then organisation secrets |
| Self-hosted runner | The above plus anything on disk, instance metadata role credentials, cached registries and Docker config | Highest: also rebuild the runner |
| Developer laptop | .npmrc, ~/.aws, gcloud and Azure CLI tokens, SSH keys, GitHub CLI tokens, browser and Slack sessions, AI coding tool credentials | High: revoke and reissue, then reimage |
| Container build | Build arguments and secrets mounted at build time, registry push credentials | Medium to high depending on what was mounted |
Revoke at the issuer, not just in your secret store: npm, GitHub, the cloud provider, Vault and each SaaS. The Shai-Hulud page records Wiz finding more than 60% of leaked npm tokens still valid a week after the second wave, which is what happens when consumers delete secrets locally but do not revoke them at source. For npm token types and their revocation, see the npm Tokens Security Guide.
Where identity fits
Every step above is about non-human identities: publishing tokens, CI secrets, workload roles and AI agent credentials. The fastest way to make the next compromise cheaper is to have fewer long-lived ones in reach of third-party code. Use OIDC federation so CI jobs get short-lived cloud credentials (see the GitHub Actions OIDC Federation Hardening Guide), keep publishing credentials out of jobs that install dependencies, and set GITHUB_TOKEN to read-only by default as GitHub recommends.
Controls that shrink the next one
| Control | Specific setting | What it would have changed |
|---|---|---|
| Disable install scripts in CI | npm ci --ignore-scripts or ignore-scripts=true; allow-list builds that need them | Shai-Hulud and ChainDrop ran from preinstall |
| Lockfile-only installs | npm ci fails if package-lock.json and package.json disagree | Stops silent upgrades to a poisoned patch version |
| Release age delay | pnpm minimumReleaseAge (minutes; default 1440) with minimumReleaseAgeExclude for internal packages | Nx malicious versions were live for about four to five hours; ChainDrop was flagged by Socket within about six minutes |
| Pin Actions to full commit SHAs | Replace @v4 with the SHA from the action's own repository | tj-actions and Trivy attacks moved tags |
| Separate install and secret-bearing jobs | No publishing or cloud admin secrets in jobs that run third-party code | Limits what a stealer can read from runner memory |
| Egress control on runners | Allow-list outbound destinations; alert on new endpoints | tj-actions was spotted from an unexpected network endpoint |
| Restrict AI CLIs on build hosts and laptops | No permission-bypass modes by default; no plaintext secrets in home directories | Nx and ChainDrop targeted AI tool credentials and modes |
For install-time controls in depth, see the npm Install-Time Security Guide.
Decision guidance
- Assume compromise or investigate first: if a host installed an affected version inside the window with scripts enabled, assume compromise and revoke. Investigation decides the scope of the hunt, not whether to revoke.
- Revoke immediately or clean first: clean first only where the malware family is documented to retaliate on revocation, and keep that delay to hours. Otherwise revoke immediately.
- Small teams: rotate everything a CI organisation holds; the list is short enough. Move to OIDC and read-only tokens as the recovery step.
- Large organisations: you need an SBOM or dependency inventory to answer exposure across hundreds of repositories. See the SBOM Guide.
Detection and measurement
- Time from public advisory to a complete exposure answer across all repositories.
- Percentage of CI pipelines running with install scripts disabled.
- Percentage of third-party Actions pinned to SHAs.
- Percentage of CI jobs using federated, short-lived cloud credentials rather than stored keys.
- Time from exposure confirmation to revocation of publishing and cloud credentials.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| MITRE ATT&CK v20 | T1195.001, T1195.002 | Compromise of dependencies and development tools; software supply chain |
| MITRE ATT&CK v20 | T1552.001, T1528 | Credentials in files; stealing application access tokens |
| NIST SP 800-53 Rev 5 | SR-4, SR-11, SI-7, CM-7 | Provenance, component authenticity, integrity, least functionality (scripts off) |
| NIST CSF 2.0 | RS.MI-01, RS.MI-02, GV.SC-07 | Containment, eradication and ongoing supplier risk monitoring |
Common failure patterns
- Deleting the secret locally without revoking it at the issuer, as the still-valid npm tokens after Shai-Hulud show.
- Ignoring ephemeral runners because the VM is gone; the secrets it held are not.
- Trusting provenance as proof of safety: ChainDrop shipped with valid provenance.
- Leaving secret-printing logs in place after the tj-actions pattern.
- Tag pinning only: the Trivy Supply Chain Attack 2026 force-pushed trivy-action tags.
Practitioner checklist
- Keep lockfiles committed for every project and searchable centrally.
- Keep CI logs for long enough to cover a campaign window.
- Run
npm ci --ignore-scriptsin CI by default. - Delay new dependency versions in automated updates.
- Pin Actions to commit SHAs and allow-list third-party Actions.
- Keep publishing and cloud admin secrets out of jobs that install dependencies.
- Prepare an issuer-by-issuer revocation list for CI and developer credentials.
- Rehearse the exposure query and revocation once a quarter.
Standards and references
- NHI Mgmt Group: The State of NHI & AI Agent Breach Report 2026 (October 2026)
- CISA: Widespread Supply Chain Compromise Impacting npm Ecosystem
- GitHub Docs: Secure use reference for GitHub Actions
- npm Docs: npm ci
- pnpm: Dependency resolution settings
- MITRE ATT&CK: T1195.002 Compromise Software Supply Chain
- NIST: SP 800-53 Rev 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Malicious Open Source Package Response Playbook, Shai-Hulud npm Worm Guide, Malicious Package and Dependency Confusion Guide, npm Trusted Publishing and Provenance Guide.