Skip to content

Instantly share code, notes, and snippets.

@xtetsuji
Created December 5, 2025 07:18
Show Gist options
  • Select an option

  • Save xtetsuji/0497498b887ef800abeb870fecd28d24 to your computer and use it in GitHub Desktop.

Select an option

Save xtetsuji/0497498b887ef800abeb870fecd28d24 to your computer and use it in GitHub Desktop.
Shai-Hulud感染チェックスクリプト
#!/usr/bin/env bash
set -euo pipefail
# ============================================
# Shai-Hulud 簡易チェックスクリプト
# - 前提:
# - gh CLI ログイン済み (gh auth login 済み)
# - jq コマンド利用可能
# - POSIX find 利用可能 (macOS / Linux 想定)
# ============================================
SCAN_DIR="${1:-.}" # 第1引数でスキャン開始ディレクトリを指定 (デフォルト: 現在ディレクトリ)
# ---- 前提チェック ----
for cmd in gh jq find; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "[ERROR] '$cmd' コマンドが見つかりません。" >&2
exit 1
fi
done
echo "=== Shai-Hulud 簡易チェックを開始します ==="
echo "スキャン対象ディレクトリ: $SCAN_DIR"
echo
# --------------------------------------------
# 1. GitHub リポジトリの簡易チェック
# - 自アカウントのリポジトリ一覧を取得
# - description に 'hulud' を含むものがないか確認
# - .github/workflows/discussion.yaml があるリポジトリを探す
# --------------------------------------------
check_github_repos() {
echo "[1] GitHub リポジトリの確認"
local user
user=$(gh api user -q .login)
echo " - 対象 GitHub ユーザー: $user"
echo " - description に 'hulud' を含むリポジトリを検索中..."
local suspicious_repos
suspicious_repos=$(
gh repo list "$user" --limit 200 --json name,description,visibility,url \
| jq -r '
map(select((.description // "") | test("(?i)hulud"))) |
if length == 0 then
"NONE"
else
.[]
| "\(.visibility)\t\(.name)\t\(.url)\t\(.description)"
end
'
)
if [ "$suspicious_repos" = "NONE" ]; then
echo " → description に 'hulud' を含むリポジトリは見つかりませんでした。"
else
echo " !!! 要確認のリポジトリがあります:"
echo "$suspicious_repos" | while IFS=$'\t' read -r vis name url desc; do
printf " - [%s] %s (%s)\n desc: %s\n" "$vis" "$name" "$url" "$desc"
done
fi
echo
echo " - .github/workflows/discussion.yaml の有無をチェック中..."
gh repo list "$user" --limit 200 --json name,owner \
| jq -r '.[] | "\(.owner.login)/\(.name)"' \
| while read -r repo; do
if gh api -X GET "repos/$repo/contents/.github/workflows/discussion.yaml" \
>/dev/null 2>&1; then
echo " !!! $repo に .github/workflows/discussion.yaml が存在します。要確認です。"
fi
done
echo " (※ 上記に何も表示されなければ、この項目に関しては特に怪しいものは見つかっていません)"
echo
}
# --------------------------------------------
# 2. ローカルの怪しいファイルチェック
# - 2025-11-21 以降に作られた/更新された
# 以下のような名前のファイルを探す:
# setup_bun.js, bun_environment.js,
# cloud.json, environment.json, actionsSecrets.json
# --------------------------------------------
check_local_files() {
echo "[2] ローカルファイルの確認"
# 攻撃が始まったとされる日付より少し前の基準ファイルを作成
local ref_file
ref_file=$(mktemp)
# 2025-11-21 00:00 を基準 (touch の書式: YYYYMMDDhhmm)
touch -t 202511210000 "$ref_file"
echo " - 2025-11-21 以降に作成/更新された怪しいファイル名を検索します..."
echo " 対象ファイル名:"
echo " - setup_bun.js"
echo " - bun_environment.js"
echo " - cloud.json"
echo " - environment.json"
echo " - actionsSecrets.json"
echo
local results
# node_modules 配下に限らず、プロジェクト全体から探す
results=$(
find "$SCAN_DIR" \
\( -name "setup_bun.js" -o -name "bun_environment.js" \
-o -name "cloud.json" -o -name "environment.json" \
-o -name "actionsSecrets.json" \) \
-newer "$ref_file" 2>/dev/null || true
)
rm -f "$ref_file"
if [ -z "$results" ]; then
echo " → 該当する怪しいファイルは見つかりませんでした。"
else
echo " !!! 要確認のファイルが見つかりました:"
echo "$results" | sed 's/^/ - /'
fi
echo
}
# --------------------------------------------
# 実行
# --------------------------------------------
check_github_repos
check_local_files
echo "=== チェック完了 ==="
echo "※ これはあくまで『簡易チェック』です。怪しい結果が出た場合は、"
echo " トークンのローテーションやリポジトリ/ランナー/ワークフローの手動確認も行ってください。"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment