Created
March 31, 2026 14:31
-
-
Save MarkKropf/c72344a9dec60081ee8cf0ffb1de8af8 to your computer and use it in GitHub Desktop.
Axios Supply Chain Compromise Scanner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ============================================================================ | |
| # Axios Supply Chain Compromise Scanner | |
| # Author: Mark Kropf | |
| # Date: 2026-03-31 | |
| # Ref: https://socket.dev/blog/axios-npm-package-compromised | |
| # https://www.aikido.dev/blog/axios-npm-compromised-maintainer-hijacked-rat | |
| # | |
| # Scans for: | |
| # 1. Malicious axios versions (1.14.1, 0.30.4) | |
| # 2. Malicious dependency packages (plain-crypto-js, @shadanai/openclaw, @qqbrowser/openclaw-qbot) | |
| # 3. macOS RAT binary: /Library/Caches/com.apple.act.mond | |
| # 4. Dropper artifacts ($TMPDIR/6202033, setup.js postinstall hooks) | |
| # 5. C2 network indicators (sfrclak.com, 142.11.206.73) | |
| # 6. All non-malicious axios installations for awareness | |
| # | |
| # Usage: sudo ./scan-axios-compromise.sh [scan_root ...] | |
| # Defaults to scanning / plus all /Volumes/* mounts | |
| # sudo recommended for full filesystem access | |
| # ============================================================================ | |
| set -euo pipefail | |
| RED='\033[0;31m' | |
| YELLOW='\033[1;33m' | |
| GREEN='\033[0;32m' | |
| CYAN='\033[0;36m' | |
| BOLD='\033[1m' | |
| NC='\033[0m' | |
| INFECTED=0 | |
| WARNINGS=0 | |
| AXIOS_FOUND=0 | |
| SCAN_START=$(date +%s) | |
| log_critical() { echo -e "${RED}[CRITICAL]${NC} $*"; ((INFECTED++)); } | |
| log_warning() { echo -e "${YELLOW}[WARNING]${NC} $*"; ((WARNINGS++)); } | |
| log_info() { echo -e "${CYAN}[INFO]${NC} $*"; } | |
| log_ok() { echo -e "${GREEN}[OK]${NC} $*"; } | |
| log_section() { | |
| local now elapsed | |
| now=$(date +%s) | |
| elapsed=$(( now - SCAN_START )) | |
| echo -e "\n${BOLD}=== $* === ${CYAN}[${elapsed}s]${NC}" | |
| } | |
| # --- Known IOCs --- | |
| MALICIOUS_AXIOS_VERSIONS=("1.14.1" "0.30.4") | |
| MALICIOUS_PACKAGES=("plain-crypto-js" "@shadanai/openclaw" "@qqbrowser/openclaw-qbot") | |
| C2_DOMAIN="sfrclak.com" | |
| C2_IP="142.11.206.73" | |
| MACOS_RAT_PATH="/Library/Caches/com.apple.act.mond" | |
| MACOS_RAT_SHA256="92ff08773995ebc8d55ec4b8e1a225d0d1e51efa4ef88b8849d0071230c9645a" | |
| LINUX_PAYLOAD_SHA256="fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf" | |
| # Store our own PID to exclude from process checks | |
| SCANNER_PID=$$ | |
| # Determine scan roots | |
| SCAN_ROOTS=() | |
| if [[ $# -gt 0 ]]; then | |
| SCAN_ROOTS=("$@") | |
| else | |
| SCAN_ROOTS=("/") | |
| if [[ -d /Volumes ]]; then | |
| for vol in /Volumes/*/; do | |
| [[ -d "$vol" ]] && SCAN_ROOTS+=("${vol%/}") | |
| done | |
| fi | |
| fi | |
| echo -e "${BOLD}============================================================${NC}" | |
| echo -e "${BOLD} Axios Supply Chain Compromise Scanner${NC}" | |
| echo -e "${BOLD} $(date)${NC}" | |
| echo -e "${BOLD}============================================================${NC}" | |
| echo "" | |
| echo "Scan roots: ${SCAN_ROOTS[*]}" | |
| echo "Scanner PID: $SCANNER_PID" | |
| echo "" | |
| # ============================================================================ | |
| # PHASE 1: Check for macOS RAT binary (fast - direct path checks + targeted find) | |
| # ============================================================================ | |
| log_section "Phase 1: Checking for macOS RAT binary" | |
| # Helper: check if the RAT process is genuinely running (not our own scanner) | |
| check_rat_process() { | |
| # Use [c] bracket trick to exclude grep, then filter out find/scanner processes | |
| local real_hits | |
| real_hits=$(ps aux | grep "[c]om.apple.act.mond" \ | |
| | grep -v -E "find |grep |pgrep |bash.*(scan|axios)" \ | |
| | grep -v "$$" || true) | |
| if [[ -n "$real_hits" ]]; then | |
| log_critical "RAT PROCESS com.apple.act.mond IS RUNNING!" | |
| echo "$real_hits" | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| check_rat_path() { | |
| local rat_path="$1" | |
| if [[ -f "$rat_path" ]]; then | |
| log_critical "RAT BINARY FOUND: $rat_path" | |
| ls -la "$rat_path" | |
| local sha | |
| sha=$(shasum -a 256 "$rat_path" 2>/dev/null | awk '{print $1}') | |
| if [[ "$sha" == "$MACOS_RAT_SHA256" ]]; then | |
| log_critical "SHA256 MATCHES known malicious RAT: $sha" | |
| else | |
| log_critical "SHA256: $sha (differs from known IOC but file exists at malicious path)" | |
| fi | |
| check_rat_process || true | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Check standard path first (instant) | |
| check_rat_path "$MACOS_RAT_PATH" || true | |
| # Check across all scan roots for Library/Caches variant (instant per root) | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| rat_candidate="${root}/Library/Caches/com.apple.act.mond" | |
| [[ "$rat_candidate" == "$MACOS_RAT_PATH" ]] && continue | |
| check_rat_path "$rat_candidate" || true | |
| done | |
| # Targeted find - only search Library/Caches directories, not entire tree | |
| log_info "Searching Library/Caches dirs for com.apple.act.mond..." | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| while IFS= read -r -d '' match; do | |
| [[ "$match" == "$MACOS_RAT_PATH" ]] && continue | |
| log_critical "RAT binary found at unexpected location: $match" | |
| ls -la "$match" | |
| shasum -a 256 "$match" 2>/dev/null | |
| done < <(find "$root" -path "*/Library/Caches/com.apple.act.mond" -print0 2>/dev/null) | |
| done | |
| if [[ $INFECTED -eq 0 ]]; then | |
| log_ok "No RAT binary found" | |
| fi | |
| # Process check (separate from file check) | |
| check_rat_process || log_ok "No com.apple.act.mond process running" | |
| # ============================================================================ | |
| # PHASE 2: Check for dropper artifacts (fast - direct path checks) | |
| # ============================================================================ | |
| log_section "Phase 2: Checking for dropper/temp artifacts" | |
| TMPDIR_ACTUAL="${TMPDIR:-/tmp}" | |
| if [[ -f "${TMPDIR_ACTUAL}/6202033" ]]; then | |
| log_critical "Dropper artifact found: ${TMPDIR_ACTUAL}/6202033" | |
| ls -la "${TMPDIR_ACTUAL}/6202033" | |
| file "${TMPDIR_ACTUAL}/6202033" 2>/dev/null | |
| else | |
| log_ok "No dropper at ${TMPDIR_ACTUAL}/6202033" | |
| fi | |
| if [[ -f "/tmp/ld.py" ]]; then | |
| log_critical "Linux payload found: /tmp/ld.py" | |
| sha=$(shasum -a 256 "/tmp/ld.py" 2>/dev/null | awk '{print $1}') | |
| if [[ "$sha" == "$LINUX_PAYLOAD_SHA256" ]]; then | |
| log_critical "SHA256 matches known malicious Linux payload" | |
| fi | |
| else | |
| log_ok "No Linux payload at /tmp/ld.py" | |
| fi | |
| # Windows artifacts on mounted volumes (depth-limited) | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| for f in $(find "$root" -maxdepth 5 \( -name "6202033.vbs" -o -name "6202033.ps1" \) 2>/dev/null); do | |
| log_critical "Dropper artifact found: $f" | |
| done | |
| done | |
| # ============================================================================ | |
| # PHASE 3: Scan for malicious and all axios installations (optimized) | |
| # Uses a single find pass with -prune to skip deep .pnpm virtual stores | |
| # ============================================================================ | |
| log_section "Phase 3: Scanning for axios installations (node_modules)" | |
| MALICIOUS_INSTALLS=() | |
| SAFE_INSTALLS=() | |
| scan_package_json() { | |
| local pkg_json="$1" | |
| local pkg_dir | |
| pkg_dir=$(dirname "$pkg_json") | |
| local name version | |
| # Fast extraction: read first 5 lines to get name/version (avoids reading full file) | |
| name=$(sed -n '/"name"/{s/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p;q;}' "$pkg_json" 2>/dev/null || echo "") | |
| version=$(sed -n '/"version"/{s/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p;q;}' "$pkg_json" 2>/dev/null || echo "") | |
| if [[ "$name" == "axios" ]]; then | |
| ((AXIOS_FOUND++)) | |
| local is_malicious=false | |
| for mv in "${MALICIOUS_AXIOS_VERSIONS[@]}"; do | |
| if [[ "$version" == "$mv" ]]; then | |
| is_malicious=true | |
| break | |
| fi | |
| done | |
| if $is_malicious; then | |
| log_critical "MALICIOUS axios@${version} found: $pkg_dir" | |
| MALICIOUS_INSTALLS+=("$pkg_dir (axios@${version})") | |
| if [[ -f "$pkg_dir/setup.js" ]]; then | |
| log_critical " setup.js (postinstall dropper) present!" | |
| if grep -q "sfrclak\|6202033\|plain-crypto" "$pkg_dir/setup.js" 2>/dev/null; then | |
| log_critical " setup.js contains known malicious indicators!" | |
| fi | |
| fi | |
| if grep -q '"postinstall"' "$pkg_json" 2>/dev/null; then | |
| log_critical " package.json has postinstall script!" | |
| grep '"postinstall"' "$pkg_json" | |
| fi | |
| else | |
| SAFE_INSTALLS+=("$pkg_dir (axios@${version})") | |
| fi | |
| fi | |
| } | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| log_info "Scanning $root for node_modules/axios ..." | |
| # Single find pass: look for axios package.json, skip .Trash/System/.cache | |
| while IFS= read -r -d '' pkg_json; do | |
| scan_package_json "$pkg_json" | |
| done < <(find "$root" \ | |
| \( -name ".Trash" -o -name "System" -o -name ".cache" \) -prune -o \ | |
| -path "*/node_modules/axios/package.json" -print0 2>/dev/null) | |
| # Malicious companion packages - targeted find for each | |
| log_info "Scanning $root for malicious companion packages..." | |
| for mpkg in "${MALICIOUS_PACKAGES[@]}"; do | |
| while IFS= read -r -d '' pkg_json; do | |
| local name | |
| name=$(sed -n '/"name"/{s/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p;q;}' "$pkg_json" 2>/dev/null || echo "") | |
| if [[ "$name" == "$mpkg" ]]; then | |
| local ver | |
| ver=$(sed -n '/"version"/{s/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p;q;}' "$pkg_json" 2>/dev/null || echo "") | |
| log_critical "MALICIOUS PACKAGE ${mpkg}@${ver} found: $(dirname "$pkg_json")" | |
| fi | |
| done < <(find "$root" \ | |
| \( -name ".Trash" -o -name "System" -o -name ".cache" \) -prune -o \ | |
| -path "*/node_modules/${mpkg}/package.json" -print0 2>/dev/null) | |
| done | |
| done | |
| log_info "Found $AXIOS_FOUND axios installations" | |
| # ============================================================================ | |
| # PHASE 4: Check package manager caches (runs once, not per-root) | |
| # ============================================================================ | |
| log_section "Phase 4: Checking package manager caches" | |
| NPM_CACHE="${HOME}/.npm" | |
| YARN_CACHE="${HOME}/.yarn/cache" | |
| PNPM_STORE="${HOME}/.local/share/pnpm/store" | |
| PNPM_STORE_ALT="${HOME}/Library/pnpm/store" | |
| check_cache_dir() { | |
| local cache_dir="$1" | |
| local label="$2" | |
| if [[ ! -d "$cache_dir" ]]; then | |
| log_info "$label not found at $cache_dir (skipping)" | |
| return | |
| fi | |
| log_info "Checking $label ($cache_dir)..." | |
| # Targeted: look for tarballs/metadata with malicious package names | |
| local found=0 | |
| # Check for plain-crypto-js | |
| local crypto_hits | |
| crypto_hits=$(find "$cache_dir" -type f -name "*plain-crypto*" 2>/dev/null || true) | |
| if [[ -n "$crypto_hits" ]]; then | |
| log_critical "Malicious package plain-crypto-js found in $label cache:" | |
| echo "$crypto_hits" | |
| ((found++)) | |
| fi | |
| # Check for malicious scoped openclaw packages only | |
| local openclaw_hits | |
| openclaw_hits=$(find "$cache_dir" -type f \( -name "*shadanai*openclaw*" -o -name "*qqbrowser*openclaw*" -o -name "*openclaw-qbot*" \) 2>/dev/null || true) | |
| if [[ -n "$openclaw_hits" ]]; then | |
| log_critical "Malicious openclaw package found in $label cache:" | |
| echo "$openclaw_hits" | |
| ((found++)) | |
| fi | |
| # Check for malicious axios tarballs by name pattern (much faster than grep-all-json) | |
| local axios_tarballs | |
| axios_tarballs=$(find "$cache_dir" -type f \( -name "*axios-1.14.1*" -o -name "*axios-0.30.4*" \) 2>/dev/null || true) | |
| if [[ -n "$axios_tarballs" ]]; then | |
| log_critical "Malicious axios tarball found in $label cache:" | |
| echo "$axios_tarballs" | |
| ((found++)) | |
| fi | |
| # Check pnpm index files for malicious axios versions (pnpm stores metadata as json) | |
| if [[ -d "$cache_dir" && "$label" == *"pnpm"* ]]; then | |
| local pnpm_idx | |
| pnpm_idx=$(find "$cache_dir" -type f \( -name "*axios@1.14.1*" -o -name "*axios@0.30.4*" \) 2>/dev/null || true) | |
| if [[ -n "$pnpm_idx" ]]; then | |
| log_critical "Malicious axios version in pnpm index: $pnpm_idx" | |
| ((found++)) | |
| fi | |
| # Check for scoped openclaw in pnpm index | |
| local pnpm_openclaw | |
| pnpm_openclaw=$(find "$cache_dir" -type f \( -name "*@shadanai*" -o -name "*@qqbrowser*" \) 2>/dev/null || true) | |
| if [[ -n "$pnpm_openclaw" ]]; then | |
| log_critical "Malicious scoped package in pnpm index:" | |
| echo "$pnpm_openclaw" | |
| ((found++)) | |
| fi | |
| fi | |
| # For npm cache: check _cacache for malicious shasums in content-addressed store | |
| if [[ "$label" == "npm cache" && -d "$cache_dir/_cacache" ]]; then | |
| for sha in "2553649f2322049666871cea80a5d0d6adc700ca" "d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71" "07d889e2dadce6f3910dcbc253317d28ca61c766"; do | |
| if find "$cache_dir/_cacache" -name "*${sha}*" 2>/dev/null | grep -q .; then | |
| log_critical "Malicious shasum $sha found in npm content-addressed cache" | |
| ((found++)) | |
| fi | |
| done | |
| fi | |
| if [[ $found -eq 0 ]]; then | |
| log_ok "$label clean" | |
| fi | |
| } | |
| check_cache_dir "$NPM_CACHE" "npm cache" | |
| check_cache_dir "$YARN_CACHE" "yarn cache" | |
| check_cache_dir "$PNPM_STORE" "pnpm store" | |
| check_cache_dir "$PNPM_STORE_ALT" "pnpm store (alt)" | |
| # Check npm global | |
| GLOBAL_NM=$(npm root -g 2>/dev/null || echo "") | |
| if [[ -n "$GLOBAL_NM" && -d "$GLOBAL_NM/axios" ]]; then | |
| log_warning "axios installed globally at $GLOBAL_NM/axios" | |
| scan_package_json "$GLOBAL_NM/axios/package.json" | |
| fi | |
| # ============================================================================ | |
| # PHASE 5: Check lock files for malicious versions/shasums | |
| # Uses ripgrep if available (10-100x faster), falls back to grep | |
| # ============================================================================ | |
| log_section "Phase 5: Scanning lock files for malicious versions/integrity hashes" | |
| MALICIOUS_SHASUMS=( | |
| "2553649f2322049666871cea80a5d0d6adc700ca" # axios@1.14.1 | |
| "d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71" # axios@0.30.4 | |
| "07d889e2dadce6f3910dcbc253317d28ca61c766" # plain-crypto-js@4.2.1 | |
| ) | |
| # Build a single combined regex for all IOCs (one grep pass per lock file) | |
| LOCKFILE_PATTERN="axios@1\.14\.1\|axios@0\.30\.4\|axios.*1\.14\.1\|axios.*0\.30\.4" | |
| LOCKFILE_PATTERN="${LOCKFILE_PATTERN}\|plain-crypto-js" | |
| LOCKFILE_PATTERN="${LOCKFILE_PATTERN}\|@shadanai/openclaw\|@qqbrowser/openclaw-qbot" | |
| LOCKFILE_PATTERN="${LOCKFILE_PATTERN}\|packages\.npm\.org" | |
| for sha in "${MALICIOUS_SHASUMS[@]}"; do | |
| LOCKFILE_PATTERN="${LOCKFILE_PATTERN}\|${sha}" | |
| done | |
| LOCKFILES_CHECKED=0 | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| while IFS= read -r -d '' lockfile; do | |
| ((LOCKFILES_CHECKED++)) | |
| # Single grep pass with combined pattern | |
| matches=$(grep -n "$LOCKFILE_PATTERN" "$lockfile" 2>/dev/null || true) | |
| if [[ -n "$matches" ]]; then | |
| log_critical "IOC match in lock file: $lockfile" | |
| echo "$matches" | head -20 | |
| fi | |
| done < <(find "$root" \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \) \ | |
| -not -path "*/node_modules/*" \ | |
| -not -path "*/.Trash/*" \ | |
| -not -path "*/System/*" \ | |
| -print0 2>/dev/null) | |
| done | |
| log_info "Checked $LOCKFILES_CHECKED lock files" | |
| # ============================================================================ | |
| # PHASE 6: Network/DNS indicators (fast - no filesystem scan) | |
| # ============================================================================ | |
| log_section "Phase 6: Checking for C2 network indicators" | |
| if grep -q "$C2_DOMAIN" /etc/hosts 2>/dev/null; then | |
| log_critical "/etc/hosts contains C2 domain: $C2_DOMAIN" | |
| fi | |
| if command -v lsof &>/dev/null; then | |
| if lsof -i -n -P 2>/dev/null | grep -q "$C2_IP"; then | |
| log_critical "ACTIVE CONNECTION to C2 IP $C2_IP detected!" | |
| lsof -i -n -P 2>/dev/null | grep "$C2_IP" | |
| else | |
| log_ok "No active connections to C2 IP $C2_IP" | |
| fi | |
| fi | |
| if command -v netstat &>/dev/null; then | |
| if netstat -an 2>/dev/null | grep -q "$C2_IP"; then | |
| log_critical "Network connection to C2 IP found in netstat!" | |
| fi | |
| fi | |
| # C2 references in source: use ripgrep if available (massively faster), else targeted grep | |
| # Only scan node_modules/axios dirs and top-level project files, not ALL source | |
| log_info "Searching for C2 domain/IP in axios packages and project configs..." | |
| C2_PATTERN="sfrclak|142\.11\.206\.73|packages\.npm\.org" | |
| if command -v rg &>/dev/null; then | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| # Fast: ripgrep with built-in parallelism, skip .git/dist/build/.cache | |
| rg_hits=$(rg -l --no-messages \ | |
| --glob '!.git' --glob '!dist' --glob '!build' --glob '!.cache' --glob '!*.min.js' --glob '!*.map' \ | |
| --glob '*.{js,ts,json,mjs,cjs}' \ | |
| -e "$C2_PATTERN" \ | |
| "$root" 2>/dev/null | head -50 || true) | |
| if [[ -n "$rg_hits" ]]; then | |
| while IFS= read -r hit; do | |
| log_critical "C2 indicator found in: $hit" | |
| rg -n "$C2_PATTERN" "$hit" 2>/dev/null | head -3 | |
| done <<< "$rg_hits" | |
| fi | |
| done | |
| else | |
| # Fallback: only grep inside axios dirs and top-level configs (not all source) | |
| for root in "${SCAN_ROOTS[@]}"; do | |
| # Check axios package dirs specifically | |
| while IFS= read -r -d '' axdir; do | |
| if grep -rlq "sfrclak\|142\.11\.206\.73\|packages\.npm\.org" "$axdir" 2>/dev/null; then | |
| log_critical "C2 indicator found in axios dir: $axdir" | |
| fi | |
| done < <(find "$root" -path "*/node_modules/axios" -type d -print0 2>/dev/null) | |
| # Check top-level package.json / lock files (already covered in phase 5 but catches package.json too) | |
| while IFS= read -r -d '' pjson; do | |
| if grep -q "sfrclak\|142\.11\.206\.73\|packages\.npm\.org" "$pjson" 2>/dev/null; then | |
| log_critical "C2 indicator in project config: $pjson" | |
| fi | |
| done < <(find "$root" -maxdepth 3 -name "package.json" -not -path "*/node_modules/*" -print0 2>/dev/null) | |
| done | |
| fi | |
| # ============================================================================ | |
| # PHASE 7: Check LaunchAgents/LaunchDaemons for persistence (fast) | |
| # ============================================================================ | |
| log_section "Phase 7: Checking for persistence mechanisms (LaunchAgents/Daemons)" | |
| LAUNCH_DIRS=( | |
| "/Library/LaunchAgents" | |
| "/Library/LaunchDaemons" | |
| "$HOME/Library/LaunchAgents" | |
| "$HOME/Library/LaunchDaemons" | |
| ) | |
| for ldir in "${LAUNCH_DIRS[@]}"; do | |
| if [[ -d "$ldir" ]]; then | |
| while IFS= read -r -d '' plist; do | |
| if grep -q "com.apple.act.mond\|sfrclak\|6202033" "$plist" 2>/dev/null; then | |
| log_critical "Persistence plist referencing malware: $plist" | |
| fi | |
| done < <(find "$ldir" -name "*.plist" -print0 2>/dev/null) | |
| fi | |
| done | |
| log_ok "Persistence check complete" | |
| # ============================================================================ | |
| # PHASE 8: Check crontabs (fast) | |
| # ============================================================================ | |
| log_section "Phase 8: Checking crontabs" | |
| if crontab -l 2>/dev/null | grep -q "com.apple.act.mond\|sfrclak\|6202033"; then | |
| log_critical "Crontab contains malware reference!" | |
| crontab -l 2>/dev/null | grep "com.apple.act.mond\|sfrclak\|6202033" | |
| else | |
| log_ok "No malware references in user crontab" | |
| fi | |
| # ============================================================================ | |
| # SUMMARY | |
| # ============================================================================ | |
| SCAN_END=$(date +%s) | |
| SCAN_DURATION=$(( SCAN_END - SCAN_START )) | |
| log_section "SCAN COMPLETE - SUMMARY" | |
| echo "" | |
| echo "Scan roots: ${SCAN_ROOTS[*]}" | |
| echo "Axios installs: $AXIOS_FOUND total found" | |
| echo "Lock files: $LOCKFILES_CHECKED checked" | |
| echo "Duration: ${SCAN_DURATION}s" | |
| echo "" | |
| if [[ $INFECTED -gt 0 ]]; then | |
| echo -e "${RED}${BOLD}!!! CRITICAL: $INFECTED infection indicator(s) detected !!!${NC}" | |
| echo "" | |
| echo "IMMEDIATE ACTIONS REQUIRED:" | |
| echo " 1. Disconnect from network immediately" | |
| echo " 2. Kill any com.apple.act.mond processes: sudo pkill -f com.apple.act.mond" | |
| echo " 3. Remove RAT binary: sudo rm -f /Library/Caches/com.apple.act.mond" | |
| echo " 4. Remove malicious axios: rm -rf <path>/node_modules/axios && npm install" | |
| echo " 5. Clear package caches: npm cache clean --force" | |
| echo " 6. Audit for credential theft - rotate all secrets/tokens/keys" | |
| echo " 7. Check git history for unauthorized commits" | |
| echo "" | |
| fi | |
| if [[ $WARNINGS -gt 0 ]]; then | |
| echo -e "${YELLOW}Warnings: $WARNINGS${NC}" | |
| fi | |
| if [[ ${#MALICIOUS_INSTALLS[@]} -gt 0 ]]; then | |
| echo "" | |
| echo -e "${RED}Malicious installations:${NC}" | |
| for m in "${MALICIOUS_INSTALLS[@]}"; do | |
| echo " - $m" | |
| done | |
| fi | |
| if [[ ${#SAFE_INSTALLS[@]} -gt 0 ]]; then | |
| echo "" | |
| echo -e "${GREEN}Non-malicious axios installations (${#SAFE_INSTALLS[@]}):${NC}" | |
| for s in "${SAFE_INSTALLS[@]}"; do | |
| echo " - $s" | |
| done | |
| fi | |
| echo "" | |
| if [[ $INFECTED -eq 0 && $WARNINGS -eq 0 ]]; then | |
| echo -e "${GREEN}${BOLD}System appears clean. No indicators of compromise found.${NC}" | |
| else | |
| echo -e "${RED}${BOLD}Review findings above and take remediation steps.${NC}" | |
| fi | |
| exit $INFECTED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment