vulnerability scanner for the shai-hulud worm, single sh script, deep fast scanning with ripgrep on linux and mac

make it executable, you dont need root ( you can for full system scan ) it will scan whatever folder it is on, you can put it on your ~home folder or your project

chmod +x shaiscan.sh
./shaiscan.sh

for the healp file just run ./shaiscan.sh -h

shaiscan.sh v2.3.0-2026-05-12 — Mini Shai-Hulud (CVE-2026-45321) detector

USAGE
  shaiscan.sh [OPTIONS]

OPTIONS
  -r DIR     Add DIR to scan roots (repeatable). Default: $PWD (current dir).
  -A         All-system preset: $HOME + (under root: /home/* or /Users/* + /root)
             + /usr/local /opt /etc, plus macOS LaunchAgents/LaunchDaemons.
  -x DIR     Exclude DIR (repeatable). Hard excludes (/proc /sys /dev /run /var/run
             /var/lock) cannot be re-added. The env var $SHAISCAN_EXCLUDE may
             carry a colon-separated list of additional paths to auto-exclude
             (handy for slow NFS/NBD/SMB mounts).
  -o FILE    Write markdown report to FILE. Default: ./shaiscan-YYYY-MM-DD.md
  -q         Quiet progress output (report still written).
  -j         Also emit JSON summary at <report>.json
  -V         Print version and exit.
  -h         Print this help and exit.

Read-only, passive detector for Mini Shai-Hulud — the npm/PyPI supply-chain worm disclosed 2026-05-11 (CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx).

One POSIX shell script. No dependencies beyond awk, find, grep. Works on Linux, macOS, and any system with a POSIX shell. Never modifies anything, never contacts the worm's C2, never escalates privileges.


Quickstart — block the C2 in your hosts file (do this first, takes 30 seconds)

Even if you never run the scanner, just blackholing the worm's command-and- control domains in /etc/hosts neutralises it on the machine you do this on. The payload can still drop, but every connection attempt to its C2 fails instantly. The exfil never lands. Your tokens never leave.

Copy-paste the block for your OS. The lines all start with 0.0.0.0 (IPv4 black hole) and :: (IPv6 black hole) — no real address, no traffic.

Linux

Open the file:

sudo nano /etc/hosts

Paste these lines at the bottom, save (Ctrl+O, Enter), exit (Ctrl+X):

0.0.0.0 git-tanstack.com
0.0.0.0 seed1.getsession.org
0.0.0.0 seed2.getsession.org
0.0.0.0 seed3.getsession.org
0.0.0.0 filev2.getsession.org
0.0.0.0 api.masscan.cloud
:: git-tanstack.com
:: seed1.getsession.org
:: seed2.getsession.org
:: seed3.getsession.org
:: filev2.getsession.org
:: api.masscan.cloud

Done. No restart needed.

macOS

Open the file:

sudo nano /etc/hosts

Paste the same block as Linux above. Save, exit. Then flush the DNS cache:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

Windows

  1. Press the Start button, type notepad, right-click Notepad, choose Run as administrator.

  2. In Notepad: File → Open, paste this path into the file-name box and press Enter:

    C:\Windows\System32\drivers\etc\hosts
    

    (If you see no file, change the file-type dropdown from "Text Documents" to "All Files".)

  3. Scroll to the bottom. Paste the same block as Linux above.

  4. File → Save.

Done. No restart needed.

Verify it worked

On any OS, this should now print 0.0.0.0 (or fail to resolve):

ping git-tanstack.com

If it shows the real IP, the file did not save — re-open as admin / with sudo and try again.


Why these six domains?

They are the worm's confirmed command-and-control endpoints. Sources: GHSA- g7cv-rxg3-hmpx and the upstream research published 2026-05-11.

Domain Role
git-tanstack.com Payload host (typosquat of tanstack.com)
seed1.getsession.org Covert C2 (abuses Session messenger network)
seed2.getsession.org Covert C2 (same)
seed3.getsession.org Covert C2 (same)
filev2.getsession.org Exfil endpoint
api.masscan.cloud Token-validity watcher

Note: the seed*.getsession.org and filev2.getsession.org domains also belong to the legitimate Session messenger project. The worm just abuses that network as a covert channel. If you use Session messenger on this machine, do not add these entries — pick a different defense (network egress filter, separate VLAN).


Why 0.0.0.0 and not 127.0.0.1?

Both work. 0.0.0.0 is better:

  • The connect call fails instantly with EADDRNOTAVAIL instead of hitting your loopback interface.
  • It does not pollute logs of any local web server / dev server you happen to be running.

Run the scanner

After you've blackholed the C2 (above), run the scanner to check for existing infection.

./shaiscan.sh

That scans the current directory. The report is written to ./shaiscan-YYYY-MM-DD.md.

To scan the whole user account:

./shaiscan.sh -A

To scan the whole system as root (catches root-owned persistence):

sudo ./shaiscan.sh -A

The script needs no sudo to be useful — it just sees less under directories that are root-only readable.

What it checks

  1. Running processes for worm names (gh-token-monitor, __DAEMONIZED, transformers.pyz, ctf-scramble*).
  2. Persistence drops in /tmp, ~/.config, ~/.claude, ~/.vscode, ~/Library/LaunchAgents, ~/.config/systemd/user, crontabs, ~/.npmrc, shell histories.
  3. Network state: active sockets to the C2 IP, /etc/hosts entries (blackhole = [OK], real-IP override = [CRIT]), DNS resolution probe (informational only).
  4. Editor / CI hook tampering: .claude/settings.json SessionStart hooks, .vscode/tasks.json folderOpen, .github/workflows/*.yml VARIABLE_STORE exfil pattern.
  5. Lockfiles (package-lock.json, npm-shrinkwrap.json, bun.lock, bun.lockb, yarn.lock, pnpm-lock.yaml) and package.json against the embedded IOC table (~110 packages, exact pinned versions).
  6. Git-URL audit for the malicious commit hash that pinned a payload host.
  7. Installed node_modules versions.
  8. Package-manager caches (bun, npm, yarn, pnpm).
  9. Python site-packages, pipx venvs, and Python lockfiles (Pipfile.lock, poetry.lock, uv.lock, requirements*.txt).
  10. Registry-config sanity (.npmrc, .bunfig.toml, .yarnrc{,.yml}).
  11. SSH authorized_keys and attack-window file mtimes (informational).
  12. Filesystem IOC string scan (ripgrep fast path, find + grep fallback).

Severity tiers

Tag Meaning
[CRIT] Confirmed compromise. Act now.
[REVIEW] Suspicious but ambiguous (e.g. a worm IOC string in a file that might be a security blog post you saved). Open the file and read context.
[CACHED] A bad tarball lives in a package-manager cache. Cache files do not run on their own; clean the cache.
[OK] A defensive measure was already in place on this host (e.g. /etc/hosts blackhole). Keep it.
[i] Informational context. Not a finding.

Exit codes

  • 0 — no CRIT and no REVIEW (clean, or CACHED-only).
  • 1CRIT or REVIEW present (read the report).
  • 2 — usage error.

CACHED does not fail the run — a tarball lingering on disk is not an infection on its own.


Run your package manager's audit too

shaiscan only knows the IOCs embedded in its own table. Your package manager pulls the live advisory feed and may flag advisories shaiscan does not have yet. Run both:

bun audit            # bun >= 1.1
npm audit
pnpm audit
yarn npm audit       # yarn berry

What the scanner will NOT do

  • It will not contact the C2, ever. No curl, no wget, no DNS query outside what your local resolver does on its own.
  • It will not modify any file on the system.
  • It will not delete a worm artifact for you. Image the disk before you start cleaning — the dropped files have forensic value.
  • It will not rotate any credentials. Read the dead-man-switch warning printed at the top of every run before you rotate anything.

If the scanner finds something

The scanner prints a red banner before any output explaining the safe order of operations:

  1. Disconnect the network first.
  2. Image the disk if forensics matter.
  3. Kill the worm processes.
  4. Remove the persistence hooks.
  5. Then rotate every credential — from a different, clean PC.

The worm includes the bluff string IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner in stolen npm tokens to discourage rotation, and installs a watcher (api.masscan.cloud) that polls token validity and reacts on revocation. Do not revoke from a network-connected, possibly-infected machine.


Authorised use

Scan systems you own or have explicit written permission to assess. Do not run against someone else's infrastructure.


Authority

IOCs sourced verbatim from the public GHSA-g7cv-rxg3-hmpx advisory and the upstream research disclosed 2026-05-11. No proprietary intel.