GhostAction 系「偽セキュリティ監査」ワークフローが混入したときの初動
メンテナ権限で .github/workflows/security-audit.yml(等)が default ブランチに直 push され、Actions シークレット窃取に加え、作業ツリーと 全 git 履歴からクラウド/AI/SaaS 鍵を正規表現で掻き集めて固定 IP へ POST する。ファイルの 15 行付近のシークレット列挙の有無で影響面を分け、両方ある前提でローテする。
いつ使うか
- リポジトリに見知らぬ
security-audit.yml/github_actions_security.ymlがある、またはコミットメッセージがAdd security audit workflow系のとき - メンテナアカウント侵害が疑われるとき(個人リポジトリだけでなく、そのアカウントが書けた org リポジトリも列挙)
- フォークを有効化した直後(上流から悪意ワークフローを継承し得る)
キャンペーンの形(防御に必要な理解)
- メンテナ資格情報の入手(手段は観測外)
- 既存ワークフローから使っている Actions シークレット名を拾い、ペイロードに埋め込む
- default ブランチへ直コミット → 任意 push(ブランチ/パスフィルタなし)や
workflow_dispatchで実行 - 収集内容:
- 継承分:
${{ secrets.NAME }}展開による Actions シークレット - 追加分:
fetch-depth: 0+git log -p --allで履歴を含む 13 種パターン掃討。AWS のAKIA/ASIA周辺 ±2 行コンテキストも取る(鍵 ID だけでなくシークレット側を狙う)
- 継承分:
トリアージ
ワークフロー 15 行付近を読む。
- シークレット名が埋まっている → Actions シークレット漏洩(Set A)を疑う
[ -n "" ]のように空 → 履歴掃討側(Set B)中心でも、両方ある前提で扱う
対応手順
Actions シークレットが載っていた場合
- ファイルに名前が出ているシークレットをすべてローテ(PAT はローテではなく 失効)
- PyPI / crates.io 等のレジストリで、露出期間中の不審な公開物を自分のビルド成果物と突合
- 当該ワークフローの Actions 実行履歴を確認。完了ランは窃取成功とみなす
リポジトリ/履歴掃討がある場合
HEADだけでなくgit log -p --all(到達可能なブランチ・タグ含む)で全履歴をスキャン- 見つかった認証情報を 13 カテゴリ分ローテ(作業ツリーから消えていても履歴にあれば露出扱い)
- AWS 鍵なら CloudTrail で露出期間以降の API・新規 IAM・予期しないリージョンを確認
共通
- 影響リポジトリすべてからワークフローを除去し、当該コミットをリバート(org 配下も)
- アカウント全体を侵害扱い: セッション・PAT・OAuth・SSH を失効し、耐フィッシング MFA を再設定
- org 監査ログで push 窓を確認し、「想定外のリポジトリ」まで権限ベースで列挙
- 送信先
193.32.204[.]199への通信を egress ログ(セルフホスト runner 含む)で狩り、ブロック - GitHub Secret Scanning+Push Protection、外部コラボの workflow 実行承認を有効化
- フォーク所有者: Actions を有効化する前に同名ワークフローの有無を確認
IoC(抜粋)
- パス:
.github/workflows/security-audit.yml/github_actions_security.yml - コミットメッセージ:
Add security audit workflow/Update security audit workflow等 - ボディ目印:
REPO=/AKIA_CTX_START/AKIA_CTX_END - C2:
193.32.204[.]199
注意点
- Actions シークレットを回しても、過去コミットに残るクラウド鍵は別問題。逆も同様
- GitHub Actions の uses をコミット SHA で固定する(pinact) や GitHub アカウント 1 つの侵害で本番まで行かれない CD 権限設計 は再発時の被害範囲を狭める平時策
- 本記事は Socket の公開調査に基づく対応チェックリストであり、攻撃手順の再現は扱わない
出典
- @SocketSecurity · 2026-10-14
- Socket 調査記事: socket.dev