Skip to content

Instantly share code, notes, and snippets.

@manuelkiessling
Last active May 12, 2026 08:36
Show Gist options
  • Select an option

  • Save manuelkiessling/9b3dd90bf673a618630f69a2a334a0c4 to your computer and use it in GitHub Desktop.

Select an option

Save manuelkiessling/9b3dd90bf673a618630f69a2a334a0c4 to your computer and use it in GitHub Desktop.
Indicator of Compromise Scan Script for Mini Shai-Hulud on macOS, see https://www.wiz.io/blog/mini-shai-hulud-strikes-again-tanstack-more-npm-packages-compromised
#!/usr/bin/env bash
# Mini Shai-Hulud / TanStack supply-chain IOC scanner — macOS
# Ref: https://www.wiz.io/blog/mini-shai-hulud-strikes-again-tanstack-more-npm-packages-compromised
RED=$'\033[0;31m'; GRN=$'\033[0;32m'; YLW=$'\033[0;33m'; BLD=$'\033[1m'; RST=$'\033[0m'
HITS=0
hit() { echo "${RED}${BLD}[HIT]${RST} $*"; HITS=$((HITS+1)); }
warn() { echo "${YLW}[WARN]${RST} $*"; }
ok() { echo "${GRN}[ OK ]${RST} $*"; }
hdr() { printf '\n%s=== %s ===%s\n' "$BLD" "$*" "$RST"; }
# Known-bad SHA256 hashes (router_init.js variants + setup.mjs)
BAD_HASHES=(
ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c
2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96
2258284d65f63829bd67eaba01ef6f1ada2f593f9bbe41678b2df360bd90d3df
)
# ── 1. Persistence ──────────────────────────────────────────────────────────
hdr "1. LaunchAgent persistence"
LA="$HOME/Library/LaunchAgents/com.user.gh-token-monitor.plist"
[[ -f "$LA" ]] && hit "Malicious LaunchAgent present: $LA" || ok "LaunchAgent absent"
# ── 2. Running processes ─────────────────────────────────────────────────────
hdr "2. Processes"
if pids=$(pgrep -f gh-token-monitor 2>/dev/null); then
hit "gh-token-monitor running — PIDs: $pids"
else
ok "No gh-token-monitor process"
fi
# ── 3. Active C2 connections ─────────────────────────────────────────────────
hdr "3. Network / C2 connections"
C2_RE="83\.142\.209\.194|git-tanstack\.com|getsession\.org"
if lsof -nP -i 2>/dev/null | grep -Eq "$C2_RE"; then
while IFS= read -r l; do
hit "Active C2 connection: $l"
done < <(lsof -nP -i 2>/dev/null | grep -E "$C2_RE")
else
ok "No active connections to known C2 (83.142.209.194 / git-tanstack.com / getsession.org)"
fi
# ── 4. Malicious payload files ───────────────────────────────────────────────
hdr "4. Payload files (router_init.js / setup.mjs)"
found_any=false
while IFS= read -r f; do
found_any=true
h=$(shasum -a 256 "$f" 2>/dev/null | awk '{print $1}')
confirmed=false
for bad in "${BAD_HASHES[@]}"; do
if [[ "$h" == "$bad" ]]; then
hit "Hash-confirmed malicious payload: $f"
confirmed=true
break
fi
done
$confirmed || warn "Suspicious filename (verify manually): $f [sha256=$h]"
done < <(find "$HOME" /tmp -maxdepth 10 \( -name "router_init.js" -o -name "setup.mjs" \) 2>/dev/null)
$found_any || ok "No router_init.js / setup.mjs found under \$HOME or /tmp"
# ── 5. Affected npm package versions ─────────────────────────────────────────
hdr "5. npm packages (known-bad versions)"
# @uipath/* covered implicitly via router_init.js scan above (same payload injection)
declare -A BAD_NPM_VERS=(
["@tanstack/react-router"]="1.169.5 1.169.8"
["@mistralai/mistralai"]="2.2.2 2.2.3 2.2.4"
)
npm_hit=false
# Collect search roots: home dir + npm global root
NPM_ROOTS=("$HOME")
if command -v npm &>/dev/null; then
groot=$(npm root -g 2>/dev/null | sed 's|/node_modules$||')
[[ -n "$groot" && "$groot" != "$HOME" ]] && NPM_ROOTS+=("$groot")
fi
while IFS= read -r pjson; do
pkg_name=$(awk -F'"' '/"name"/{print $4; exit}' "$pjson" 2>/dev/null)
pkg_ver=$(awk -F'"' '/"version"/{print $4; exit}' "$pjson" 2>/dev/null)
[[ -z "$pkg_name" || -z "$pkg_ver" ]] && continue
for pkg in "${!BAD_NPM_VERS[@]}"; do
[[ "$pkg_name" == "$pkg" ]] || continue
for bad_ver in ${BAD_NPM_VERS[$pkg]}; do
if [[ "$pkg_ver" == "$bad_ver" ]]; then
hit "Affected npm package installed: ${pkg}@${pkg_ver} [$pjson]"
npm_hit=true
fi
done
done
done < <(
for root in "${NPM_ROOTS[@]}"; do
find "$root" \( \
-path "*/node_modules/@tanstack/react-router/package.json" -o \
-path "*/node_modules/@mistralai/mistralai/package.json" \
\) 2>/dev/null
done | sort -u
)
$npm_hit || ok "No known-bad npm package versions found"
# ── 6. Python packages ───────────────────────────────────────────────────────
hdr "6. Python packages"
py_hit=false
for pip_cmd in pip3 pip; do
command -v "$pip_cmd" &>/dev/null || continue
for spec in "guardrails-ai 0.10.1" "mistralai 2.4.6"; do
pkg="${spec% *}"; ver="${spec##* }"
installed=$("$pip_cmd" show "$pkg" 2>/dev/null | awk '/^Version:/{print $2}')
if [[ "$installed" == "$ver" ]]; then
hit "Affected Python package: ${pkg}==${ver} (via $pip_cmd)"
py_hit=true
fi
done
break # one pip invocation is enough
done
$py_hit || ok "No known-bad Python package versions found"
# ── 7. IDE / config contamination ───────────────────────────────────────────
hdr "7. Config & IDE directory contamination"
IOC_PAT="git-tanstack|getsession\.org|gh-token-monitor|83\.142\.209\.194"
for target in "$HOME/.claude" "$HOME/.vscode" "$HOME/.npmrc" "$HOME/.env"; do
[[ -e "$target" ]] || continue
if grep -rqE "$IOC_PAT" "$target" 2>/dev/null; then
while IFS= read -r f; do
hit "IOC string found in: $f"
done < <(grep -rlE "$IOC_PAT" "$target" 2>/dev/null)
else
ok "Clean: $target"
fi
done
# ── Summary ──────────────────────────────────────────────────────────────────
hdr "Summary"
if [[ $HITS -eq 0 ]]; then
printf '%s%sNo indicators of compromise detected.%s\n' "$GRN" "$BLD" "$RST"
else
printf '%s%s%d indicator(s) of compromise found — investigate immediately.%s\n' "$RED" "$BLD" "$HITS" "$RST"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment