EXPEL BLOG

Stories from the SOC: The second coming of Shai Hulud

alt=""

· 6 MIN READ · ISA JUDD AND BEN NAHORNEY · DEC 23, 2025

TL;DR 

  • Several weeks after a new variant of Shai Hulud was discovered, we have fielded multiple incidents and developed effective approaches to remediate the threat.
  • This is an end-to-end breakdown of Shai Hulud, from initial infection to credential harvesting, GitHub-based C2, and automated self-propagation.
  • We also discuss the implications of threats like Shai Hulud and what we see on the horizon for this attack front. 

 

In the SOC, you get used to the noise. Failed logins, policy violations, the usual background static—they’re all part of the day-to-day routine. But every once in a while, something stands out.

A couple weeks ago a single string cut through the noise: SHA1HULUD. It felt like seeing a ghost; a callback to a campaign we thought was buried. We traced the activity to a public GitHub repository, hoping for a false positive. It wasn’t. Inside, hidden behind layers of Base64 encoding, was a nightmare scenario: the customer’s private cloud keys and secrets, staged in a public place for the whole world to see. It’s the type of incident no one wants to experience.

It’s been a few weeks since this new variant of Shai Hulud first appeared, but we’ve continued to see incidents involving compromised NPM packages since then. After fielding several incidents, here’s a rundown of what we’ve been seeing, along with the approach we’ve developed to identify Shai Hulud activity and put a stop to it. 

 

Overview 

First off, let’s cover how Shai Hulud: The Second Coming, as it’s come to be known, works end-to-end. 

Shai Hulud automates the compromise of the NPM ecosystem and developer environments by combining credential harvesting and rapid data exfiltration via trojanized NPM packages. Once active, it deploys the TruffleHog scanning tool to hunt for API keys and tokens, which are then exfiltrated and dumped to a public GitHub repository. 

Simultaneously, it hijacks the user’s environment to publish new malicious packages to the NPM registry, ensuring the infection spreads to other developers while exfiltrating stolen data. This campaign has spread across more than 25,000 repositories and compromised hundreds of packages, including popular projects from AsyncAPI, Zapier, PostHog, and Postman.

 

How it works 

The infection campaign in this second iteration of Shai Hulud has evolved to trigger immediately upon the execution of npm install by a developer or CI/CD system. The attack mechanism relies on a two-stage delivery system initiated by a preinstall script in the package.json

 

Stage 1: Staging

The first stage is the environment-aware setup_bun.js dropper, which runs automatically during installation to prepare the victim’s environment by ensuring the Bun runtime is installed and available. This is critical because the Bun runtime is essential for executing JavaScript code outside of a web browser.

 

Stage 2: The engine

Once the environment is staged, the dropper attempts to hand off execution to the second stage: the bun_environment.js payload. This 480,000+ lines of obfuscated malicious code runs as a detached background process and is the core payload of the Shai Hulud attack. Once executed, this script orchestrates a complex attack chain involving three main phases: credential harvesting, C2 exfiltration, and self-propagation. 

 

1. Credential harvesting & secret discovery: The malware immediately initiates a deep scan of the infected system to harvest sensitive credentials. It targets standard configuration paths and environment variables known to host high-value secrets:

  • Cloud credentials: It scans for cloud provider keys in standard locations (such as ~/.aws/credentials, ~/.azure/azureProfile.json, and ~/.config/gcloud/application_default_credentials.json.
  • Package registry tokens: It actively hunts for publishing tokens in ~/.npmrc files and scrapes environment variables for NPM_TOKEN or >NODE_AUTH_TOKEN.
  • Version control secrets: It extracts GitHub authentication tokens from the ~/.config/gh/hosts.yml file and cached git credentials.
  • Cloud secret stores: Uniquely, if it successfully steals cloud credentials, it uses the official AWS, Azure, and Google Cloud SDKs to query remote secret managers (like AWS Secrets Manager and Azure Key Vault) to dump stored secrets directly from the cloud.
  • Filesystem scanning via TruffleHog: To find secrets hidden outside of standard paths, the malware downloads and executes the TruffleHog security tool. It saves the binary to a hidden directory (e.g., ~/.truffler-cache/) and aggressively scans the user’s entire home directory for high-entropy strings, uncovering API keys, passwords, and tokens buried in source code, .env files, and git history.

2. Command and control via GitHub: The malware abuses the GitHub API to blend in with legitimate traffic.

  • Traffic blending: Unlike traditional malware that beacons to suspicious IP addresses, Shai Hulud relies entirely on legitimate GitHub Actions infrastructure. By using standard HTTPS long-polling to api.github.com, the command and control traffic becomes indistinguishable from normal developer activity, effectively bypassing firewalls and network anomaly detection tools that trust traffic to GitHub.

3. Exfiltration: It creates new, randomly named public repositories, on prior victims’ GitHub accounts chosen at random, with the description “Sha1-Hulud: The Second Coming“. It then uploads the stolen credentials to these repositories in files named:

  • contents.json: Aggregates system metadata such as platform details, hostname, OS user information, and GitHub authentication status.
  • environment.json: Dumps all environment variables, capturing cloud credentials, API keys, database strings, and other sensitive config data.
  • cloud.json: Contains secrets retrieved from AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault, showing that the malware uses stolen credentials to access cloud-native secret stores.
  • truffleSecrets.json: Stores TruffleHog scan results, including hardcoded secrets found in source code, config files, and other documents within the user’s home directory.

4. Persistence: It registers the infected machine as a self-hosted GitHub Actions runner named SHA1HULUD. This gives the attacker a persistent backdoor, allowing them to execute arbitrary remote commands on the victim’s machine simply by creating a “Discussion” in the controlled repository, which triggers a malicious workflow (.github/workflows/discussion.yaml).

5. Self-propagation: To sustain the supply chain attack, the malware weaponizes the victim’s own access. Using the harvested npm tokens, it queries the registry for other packages maintained by the victim. It then downloads these packages, injects the setup_bun.js and bun_environment.js payloads, automatically increments the patch version, and publishes the new infected versions back to npm, creating an automated cycle of infection.

 

Recommendations & remediations

Infections by this Shai Hulud variant can propagate across a network in minutes. If you have identified any IOCs related to this campaign, we recommend following the remediations below: 

  • Rotate all credentials & secrets
    • Revoke and regenerate npm tokens, GitHub personal access tokens, SSH keys, and cloud provider credentials.
    • Enforce phishing-resistant MFA for developer and CI/CD accounts. 
  • Find and remove compromised packages
    • Remove <node_modules and clear the npm cache using npm cache clean –force on all developer machines and build servers
    • Pin dependencies to exact versions or roll back to lockfiles (package-lock.json) generated prior to November 21, 2025
  • Audit GitHub & CI/CD infrastructure
    • Scan .github/workflows/ for unauthorized files (shai-hulud-workflow.yml) and immediately remove any unknown self-hosted runners, specifically looking for runners named SHA1HULUD
    • Search your organization for newly created public repositories containing Shai-Hulud in the description.
  • Pipeline hardening
    • Disable scripts by running installs with –ignore-scripts or restrict lifecycle scripts (preinstall/postinstall) in CI environments to prevent arbitrary code execution.

 

Long-term implications

Shai Hulud has raised a new attack vector in the realm of supply chain attacks. In previous supply chain attacks, bad actors would often infiltrate an organization and then manually compromise individual packages to distribute their malicious code. Shai Hulud, in using a package manager such as NPM, turns developers into the distribution point, compromising their accounts and implanting malware into any packages they maintain.

It’s also been quite a while since we’ve seen a worm have an impact like this. Sure, there’s been limited activity over the years, such as some local network functionality seen in Ryuk in 2021, but we really have to go back to WannaCry and NotPetya for anything of significance.

But Shai Hulud is a different animal—instead of attacking the network layer, you could argue that it targets the “trust layer” of the software supply chain. Until recently, few security teams considered NPM packages a serious threat in their organization’s security footprint. Going forward, these platforms and packages will require further scrutiny.

With this in mind, it’s important to note that while this style of supply chain attack has first appeared leveraging NPM, it’s likely to crop up elsewhere. The fact is, NPM is one of many programming language ecosystems that work on similar trust models, making them susceptible to similar attacks. Python has PyPi, Ruby has RubyGems, PHP has Composer, and the list goes on.

Moving forward, security teams will need to keep an eye out for future NPM attacks like Shai Hulud, as well as attacks against similar ecosystems that bad actors will likely target in a similar fashion. 

Indicators of compromise (IOCs)

File name SHA1

setup_bun.js

d1829b4708126dcc7bea7437c04d1f10eacd4a16

bun_environment.js

3d7570d14d34b0ba137d502f042b27b0f37a59fa
d60ec97eea19fffb4809bc35b91033b52490ca11

 

References