BYBOWU > Blog > Security

Shai‑Hulud 2.0: What Dev Teams Must Do This Week

blog hero image
A new wave of the Shai‑Hulud npm malware is rolling through popular packages and CI systems. It’s nastier, faster, and explicitly designed to steal tokens and re‑publish compromised packages at scale. Here’s what changed this week, what the numbers actually look like, and a step‑by‑step plan you can run in the next 60 minutes to contain risk—whether you ship JavaScript every day or just depend on it in your build.
📅
Published
Nov 29, 2025
🏷️
Category
Security
⏱️
Read Time
12 min

The primary keyword here is simple: Shai‑Hulud 2.0. If you ship JavaScript or run Node in CI, the new wave matters right now. Since November 24, 2025, researchers and vendors have confirmed a rapid second campaign that compromises maintainer accounts, plants preinstall hooks, steals CI/CD and cloud secrets, and republishes tainted packages within minutes. The payload is new, the propagation is faster, and the cleanup bill grows with every unattended pipeline run.

Diagram of the Shai‑Hulud 2.0 npm attack path using preinstall hooks

What changed in Shai‑Hulud 2.0 compared to September?

The first incident in mid‑September seeded a worm into npm via postinstall scripts and a large obfuscated bundle.js. This time, the attacker moved earlier in the lifecycle and split the payload. You’ll see two noisy artifacts:

  • setup_bun.js — a dropper disguised as a Bun installer.
  • bun_environment.js — a ~10MB, heavily obfuscated core payload executed via Bun.

Shai‑Hulud 2.0 also improves evasion and spread. Instead of predictable repo names, it creates randomized GitHub repositories to dump secrets, making detection by simple pattern searches harder. The variant leans on CI, harvesting tokens and service credentials from environment variables, then turns around and publishes malicious versions of any npm package the stolen tokens can touch—often dozens in a single run. Some analyses also describe destructive logic that triggers only under certain conditions, including attempts to overwrite the victim’s home directory when persistence fails.

Who’s actually affected and by how much?

By the afternoon of November 24–25, multiple research teams reported thousands of new repos containing encoded secrets linked to the attack. Depending on snapshot time and methodology, counts ranged from roughly 25,000 to 27,000 public GitHub repositories created during the second wave. Package‑side tallies varied, too: one major team logged just over 600 compromised packages across 800+ versions; others tracked closer to 700 and, in some lists, more. The names have included well‑known scopes—AsyncAPI, ENS Domains, Zapier, PostHog, Postman—and many smaller community maintainers. A common estimate put unique affected maintainer accounts around the mid‑hundreds during peak hours.

Two important caveats: (1) these numbers were changing hour‑to‑hour as takedowns and new publications raced each other; and (2) your risk surface depends less on a headline count and more on whether any infected version ever entered your supply chain—directly or transitively—then ran in a context with real tokens.

Is the Bun runtime compromised?

No. The attacker uses Bun as a convenient execution environment. The preinstall hook fetches or invokes Bun to run the malicious bun_environment.js. That’s it. Treat references to Bun in this context as an IOC, not as an indictment of Bun itself.

Is this about npm itself or stolen credentials?

Mostly credentials. The core theme is compromised maintainer accounts and tokens—npm, GitHub, and cloud. Once tokens leak from a developer laptop or a permissive CI environment, the worm has everything it needs: publish to npm, push to GitHub, manipulate Actions, and harvest more secrets. Some organizations halted the spread quickly by disabling lifecycle scripts in CI and rotating tokens organization‑wide. Others saw cascading republish events as build agents kept running unattended with broad privileges.

The 60‑minute triage plan (run this today)

Here’s a practical, time‑boxed flow any engineering leader can drive. The goal is to stop the bleeding, reduce blast radius, and buy time for deeper forensics.

Minutes 0–15: Hit the brakes and isolate

  • Temporarily pause CI pipelines that run npm install or pnpm/yarn installs on commit. If you can’t stop all of them, at least block new deployments and cron‑triggered builds.
  • Force all Node installs to skip scripts: set NPM_CONFIG_IGNORE_SCRIPTS=1 (or run npm install --ignore-scripts) at org level for CI. For Yarn, set --ignore-scripts where available; for pnpm, use --ignore-scripts as well.
  • Broadcast a Slack/Teams message: don’t run package installs locally until a green light is issued.

Minutes 15–30: IOC sweep in repos and runners

  • Search your org for malicious files: setup_bun.js and bun_environment.js anywhere under node_modules and cached build artifacts.
  • Audit .github/workflows for unexpected files such as discussion.yaml or random formatter_*.yml created recently.
  • List self‑hosted runners and look for suspicious names, especially any referencing "shai" or similar patterns; revoke unknown runners immediately.
  • Check your GitHub org for public repos created in the past 72 hours by unexpected actors. If you find repositories with encoded dumps or odd descriptions, presume compromise and file an internal incident ticket.

Minutes 30–45: Token lockdown and rotation

  • Revoke npm tokens for affected maintainers. Replace them with granular, short‑lived credentials or, ideally, switch projects to Trusted Publishing (OIDC) so CI never stores a long‑lived token.
  • Rotate GitHub PATs, App private keys, and environment secrets tied to Actions. Prioritize org‑level secrets used by many repos.
  • Rotate cloud credentials (AWS, GCP, Azure) exposed to CI. Invalidate sessions and require re‑auth for federated roles, focusing on the identities your pipelines assume.

Minutes 45–60: Clean installs and dependency cuts

  • For priority services, delete node_modules and lockfiles, then reinstall with scripts disabled. Manually remove any identified bad versions from package.json and regenerate a clean lockfile.
  • Vendor or pin critical dependencies to known‑good versions. If a package’s scope shows up on any public watchlists from this week, hold upgrades until the maintainer posts a signed remediation note.
  • Turn on organization‑wide secret scanning and alerting for new commits and new repos. Raise failures to blocking for pipelines that attempt to run lifecycle hooks.

How do I know if I’m compromised?

Use indicators and quick checks:

  • You find setup_bun.js or bun_environment.js in a project, build image, or runner cache.
  • Unexpected GitHub repositories suddenly appear under your account or org, sometimes with opaque names and large Base64 blobs in files.
  • Your workflows directory contains new YAML files you didn’t review.
  • npm packages in your org were republished unexpectedly in the last 72 hours, especially with patch versions that no one on your team authorized.
  • Build logs show unknown curl or bash activity pulling large blobs during install, or attempts to install Bun where it wasn’t previously used.

If any of the above is true, assume credentials or runners are compromised. Isolate first; investigate second.

A fast, defensible dependency policy for the next 7 days

Here’s a blunt but effective short‑term policy while the dust settles:

  • Freeze upgrades to any package from a scope that appears in current incident lists unless the maintainer has posted a clear remediation (and you’ve reviewed diffs).
  • Prefer npm ci with scripts disabled in CI. In production build steps, fail hard on any attempt to run lifecycle hooks unless explicitly whitelisted.
  • Use --omit=dev or equivalent in production images to reduce attack surface. Dev dependencies are frequent vehicles for install‑time malware.
  • Rebuild base images for Node services with today’s date. Don’t rely on cached layers built earlier in the week.
Developer incident response dashboard at night during an npm malware outbreak

Token hygiene: what “good” looks like after this week

Shai‑Hulud 2.0 is a wake‑up call that long‑lived, over‑scoped tokens are no longer acceptable defaults.

  • Adopt npm Trusted Publishing (OIDC) so your CI exchanges short‑lived tokens per publish. No static secrets in the repo or runner.
  • Scope everything: npm tokens to specific packages; GitHub PATs to specific repos and permissions; cloud creds to least‑privileged roles. Enforce expirations measured in days, not months.
  • Require passkeys/WebAuthn for maintainer accounts. Enforce organization‑wide 2FA and session timeouts.
  • Separate build and publish identities. A build agent that runs tests doesn’t need publish rights.
  • Turn on secret scanning and push protection for both code and Actions artifacts. Treat red findings as release blockers.

People also ask: Will disabling scripts break all my installs?

Sometimes—but that’s the point. The temporary breakage highlights which dependencies rely on install‑time execution. Each one should be reviewed and whitelisted explicitly. Many projects can ship fine with scripts disabled in CI and only enable them in a controlled packaging step.

People also ask: How long should we freeze upgrades?

Short freezes work best: 48–72 hours for initial triage, followed by a staged thaw where each dependency change is reviewed. If a package scope you rely on was confirmed in this wave, wait for the maintainer’s signed remediation and consider pinning to a pre‑incident version while you engage them.

A pragmatic review checklist for maintainers

If you publish to npm, run this before pushing any remediation release:

  • Audit npm access: who can publish, via what mechanism, and with what token lifetime?
  • Rotate credentials and invalidate classic tokens. Move CI to OIDC‑based publishing. Require code owners for package.json and workflow changes.
  • Add a prepare/prepublishOnly guard that refuses to publish if a long‑lived token is detected.
  • Publish a signed advisory in the repo and the registry that lists affected versions, clean versions, and how consumers can validate integrity.

What about transitive dependencies and SBOMs?

This is where SBOMs earn their keep. Generate a fresh SBOM for each critical service and store it with the artifact. Compare SBOMs across builds this week to surface unexpected package inflows. If you don’t have SBOM automation yet, start by producing CycloneDX from your package manager and storing it alongside the image in your registry.

Business impact: translating tech risk for executives

Expect three concrete line items this week: (1) engineering capacity diverted to incident response; (2) potential downtime or slowed delivery while scripts are disabled; and (3) cloud and SaaS credential rotation work, possibly triggering temporary access issues. The right conversation is not “Do we pause work?” but “Which systems are revenue‑critical and must be cleaned first?” Assign a single incident commander and a comms channel per product area. Timebox decisions. Green‑light purchases only if they reduce mean‑time‑to‑detect or enable OIDC publishing immediately.

Let’s get practical: a minimal supply‑chain guardrail stack

Here’s a no‑nonsense stack you can stand up in a day:

  • Organization‑wide script policy in CI: default to --ignore-scripts, opt‑in per project.
  • OIDC/Trusted Publishing for npm releases; deny classic tokens at the org boundary.
  • Required reviews for workflow files and package.json changes; block force‑pushes to default branches.
  • Secret scanning + push protection everywhere (including private repos) with on‑call paging for new leaks.
  • Nightly dependency diff report against lockfiles; flag new scopes or install scripts.

What to do next (developers)

  • Run a full reinstall with scripts disabled and audit your lockfile for any affected scopes from this week.
  • Search your org for recent repo creations you don’t recognize; report and remove.
  • Rotate every token you’ve ever stored in a dev machine or CI variable. Yes, all of them.
  • Move publish pipelines to OIDC and drop long‑lived tokens permanently.

What to do next (engineering leaders)

  • Make “ignore install scripts in CI” the default by policy, not suggestion.
  • Fund immediate OIDC migration for npm publishing and cloud roles.
  • Schedule a 72‑hour dependency freeze with a staged thaw and explicit approvals.
  • Set and publicize incident SLAs: detection in minutes, token rotation measured in hours, org‑wide review in days.

Related deep dives and help

If you need a structured incident checklist, see our earlier playbook Shai‑Hulud 2.0: The npm Supply Chain Attack Playbook. For a recent “drop everything and fix it” example in mobile tooling, our note on the React Native CLI vulnerability shows how to drive same‑day remediation. If you’d like support hardening CI, dependency governance, or OIDC rollout, our team’s approach is outlined on what we do—and you can reach us directly via contacts.

FAQ for auditors and compliance folks

What dates should our post‑incident review cover?

Start with November 21–29, 2025 to be safe. Pull logs and artifact manifests for all builds, deploys, and publishes. Preserve runner images for forensics if you can.

Which evidence should we retain?

Lockfiles, build logs, workflow logs, newly created repos, and any artifacts that contained or referenced setup_bun.js or bun_environment.js. Include tickets documenting token rotations and access changes.

Do we need to notify customers?

If secrets tied to customer environments were exposed (e.g., cloud keys, database credentials, API tokens), assume yes. Prepare rotation timelines, impacted service lists, and compensating controls. Share which dependencies and versions were involved and how you validated clean rebuilds.

The uncomfortable truth—and why this will keep happening

Package managers weren’t built to police what a maintainer does in an install script, and CI pipelines weren’t built to treat dependencies as adversarial executables. Shai‑Hulud 2.0 exploited that gap. The fix isn’t a single patch; it’s a set of norms: default‑deny install scripts in CI, stop using long‑lived tokens, and isolate publishing behind federated identities. The teams that adopt those norms turn a headline into a non‑event. Everyone else rolls the dice every time npm install runs.

Before/after hardening of CI against npm supply chain attacks

If you’ve read this far, do one thing before you switch tabs: set --ignore-scripts in CI and revoke any token older than a week. Then hand this article to the person who owns your release process. That’s how you turn Shai‑Hulud 2.0 into a blip, not a breach.

Written by Viktoria Sulzhyk · BYBOWU
2,271 views

Work with a Phoenix-based web & app team

If this article resonated with your goals, our Phoenix, AZ team can help turn it into a real project for your business.

Explore Phoenix Web & App Services Get a Free Phoenix Web Development Quote

Get in Touch

Ready to start your next project? Let's discuss how we can help bring your vision to life

Email Us

[email protected]

We typically respond within 5 minutes – 4 hours (America/Phoenix time), wherever you are

Call Us

+1 (602) 748-9530

Available Mon–Fri, 9AM–6PM (America/Phoenix)

Live Chat

Start a conversation

Get instant answers

Visit Us

Phoenix, AZ / Spain / Ukraine

Digital Innovation Hub

Send us a message

Tell us about your project and we'll get back to you from Phoenix HQ within a few business hours. You can also ask for a free website/app audit.

💻
🎯
🚀
💎
🔥