本文へ移動
情シスのミカタ
ニュース約9分で読めます

GitHubトークン悪用の「Gheist」 非公開リポジトリでシークレット流出

盗まれたGitHubのトークンで、触れるリポジトリすべてにワークフローを1つ足し、シークレットを実行ログに書き出させる攻撃「Gheist」を、Wiz Researchが報告しました。公開リポジトリではGitHubの承認待ちで止まりましたが、非公開リポジトリとGitHub Enterprise Serverでは実行されています。自社での探し方と、見つかったときに入れ替える範囲を整理します。

公開 情シスのミカタ編集部AIにより執筆チェック済み報道から
文字

報道をもとにまとめた記事です。当事者の公式の発表は確認できていません。公式の発表が出たら、それをもとに書き直します。

GitHubトークン悪用の「Gheist」 非公開リポジトリでシークレット流出

この記事のまとめ

  • Wiz Researchによると、Gheistは9月15日から続く攻撃で、850を超えるアカウントで1万3,500本を超えるブランチが見つかりました。10月24日の時点でも攻撃は続いています。
  • ci-sync-で始まるブランチにsync-check.ymlを置き、シークレットをbase32に変えて実行ログに出させます。GitHubのAPIでログを取り、数秒で実行を消すため、外部への通信がありません。
  • GitHubが7月28日に始めた承認の保留は、github.comの公開リポジトリだけが対象です。非公開リポジトリとGHESは、ブランチ・監査ログ・クラウドの記録で探し、見つかればシークレットをすべて入れ替えます。
こんな方に#20代#30代#40代#50代実務

1万3,500本を超える不審なブランチが、850を超えるアカウントのリポジトリで見つかりました。どれも、盗まれたGitHubのトークンで作られたものです。クラウドセキュリティ企業Wizの調査チーム(Wiz Research)は10月25日(米国時間)、この攻撃を「Gheist」と名付けて報告しました。攻撃のツールがGitHubのAPIに送るUser-Agentが「gheist」で、名前はそこから取っています。

Gheistは、トークンで書き込めるリポジトリすべてにワークフローを1つ足し、そのリポジトリのシークレットを実行ログに書き出させます。GitHubが7月に始めた保護機能で、公開リポジトリでは止まりました。一方、非公開リポジトリとGitHub Enterprise Server(GHES)ではワークフローが実行され、その後のクラウドへの侵入にもつながっていました。Wizによると、10月24日の時点でも攻撃は続き、手口も変わり続けています。

1つのファイルで、シークレットを実行ログに書き出させる

ツールは、リポジトリごとに「ci-sync-」と6文字のランダムな文字を続けたブランチを作り、.github/workflows/sync-check.ymlを1つだけコミットします。コミットの文言は「ci: sync config」で、署名はなく、作成者はトークンの持ち主になっています。このpushをきっかけに、ワークフローが動きます。

ワークフローは、ランナーの環境変数と、リポジトリのシークレットをまとめたもの(toJSON(secrets))を、base32という形式に変えて実行ログに出力します。Wizは、この手口が通る理由を3つ挙げています。

  • GitHubがログの中のシークレットを伏せ字にするのは、値がそのまま出たときだけです。base32に変えた値は一致しないため、そのまま出ます。
  • ワークフローに「permissions: {}」と書くと、ジョブが使うGITHUB_TOKENの権限は絞られますが、シークレットは読めます。攻撃者はGITHUB_TOKENを必要としていません。
  • リポジトリにデプロイ用の環境(environment)があると、ツールは環境ごとにジョブを並べます。本番の認証情報を置くことが多い、環境のシークレットまで出力させます。

ツールはGitHubのAPIで実行ログを取得し、数秒後に実行の記録を削除します。シークレットはGitHub自身のAPIを通って持ち出されるため、ブロックできる攻撃者のドメインも、外向きの通信もありません。

企業の組織では、ツールが数分のうちに複数の利用者や自動化用アカウントのトークンを切り替え、非公開リポジトリを複製してからワークフローを置いていました。数時間後には、同じ会社のクラウドの認証情報で、AWS Secrets Managerの中身が列挙されていたといいます。

図解。題は、盗まれたトークン1つで、触れるリポジトリすべてのシークレットを実行ログに出させる。Wiz Researchが9月15日から追跡、時点は2026年10月24日。攻撃の流れ: 1 盗まれたトークン(インフォスティーラーの記録や、3月のTrivyの侵害など過去のサプライチェーン攻撃で漏れたもの)。2 ci-sync-に6文字が続くブランチに.github/workflows/sync-check.ymlをコミット、文言はci: sync config、署名なし。3 pushでワークフローが動き、環境変数とシークレットをbase32に変えて実行ログに出す。伏せ字は元の値と同じ文字列にしか効かず、permissions: {}でもシークレットは読める。4 GitHubのAPIでログを取得し、数秒後に実行を削除。企業では数時間後にAWS Secrets Managerを列挙。公開リポジトリは7月28日からの承認の保留の対象で、Wizが確かめた実行はすべて承認待ちで止まった。非公開リポジトリとGHESは対象外で、実行が完了し削除された記録が監査ログに残り、会社自身のワークフローもAWSのロールを引き受けた。集計: 被害のアカウント850超、見つかったブランチ1万3,500超、GitHubで使えなくなったアカウント約3分の2。探す目印: ブランチ、監査ログ、クラウドの記録、セルフホストランナーの.gdmp_patなどのファイル。まとめ: 実行やブランチを消しても漏れたシークレットは戻らない。見つかったらすべて入れ替える
Gheistの攻撃の流れと、公開・非公開で分かれた結果、探す目印作成: 編集部 / 出典: Wiz Research、GitHub Changelog

9月から10月にかけて、手口が変わった

Wizは、並行して動く2つの版を見つけています。見分け方はブランチ名の末尾で、Tool Aは16進数、Tool Bは英小文字と数字(36進数)です。Tool Bは、9月28日に初めて動いてから数時間のうちに、6分で打ち切る設定と、環境ごとにジョブを並べる処理を足しました。

10月19日には、Tool Bがもう1つのジョブ「sync-host」を加えました。実行先はセルフホストランナー(自社で用意したActionsの実行用サーバー)で、ランナーを登録しているリポジトリだけをねらったとみられます。このジョブは、.gdmp_pat・.gdmp_patg・.gdmp_sweepの3つのファイルを書き、次のものを集めようとします。

  • サーバーの情報と、crontabの内容
  • 31種類の形式のトークン、秘密鍵、.envファイル、Terraformのstateファイル、シェルの履歴。ホームディレクトリなどを順にたどって探し、AIサービスではAnthropic、Hugging Face、Groq、NVIDIAなどのAPIキーも対象です
  • すべてのプロセスの環境変数
  • Dockerのソケットを使って、ホストのファイルシステムをマウントしたコンテナを作り、ホストでも同じ検索
  • AWSのインスタンスロールの認証情報と、GCP・Azureのメタデータ
  • GitHub ActionsとGitLabのランナーの認証情報のファイル、Kubernetesのサービスアカウントのトークン

もっとも、このジョブには不具合があります。Wizによると、ランナーの鍵のファイルを取り違えている、URLに含まれる認証情報を拾う正規表現が壊れている、GCPとAzureのトークンを取れていない、の3点です。

公開リポジトリでは止まり、非公開リポジトリでは動いた

GitHubは7月28日から、公開リポジトリで悪意がありそうなワークフローの実行を保留し、書き込み権限のある共同作業者の承認を待つようにしました。承認は、ログインしたブラウザーからだけ受け付けます。Wizが確かめた公開リポジトリのGheistの実行は、セルフホストランナーのジョブも含めて、すべて承認待ち(action_required)のままでした。保護機能が働き、悪意のある処理は1度も動いていません。

ただし、GitHubの発表のとおり、この保留はgithub.comの公開リポジトリだけが対象で、GHESにはありません。Wizは非公開リポジトリとGHESで、ci-sync-のブランチの実行が完了し、User-Agent「gheist」の操作で削除された記録を、GitHubの監査ログで確認しています。AWSの操作記録(CloudTrail)にも、そのブランチで会社自身のワークフローが動き、AWSのロールを引き受けた記録がありました。承認なしにActionsが動いた証拠です。

同じアカウントを、ほかの攻撃者も使っている

Wizは、Gheistに使われたアカウントが、ほかの攻撃でも使われているとして、次の重なりを挙げています。

  • 10月6日、391のアカウントが約1,461のリポジトリを、fl-studio-crackのような海賊版ソフトを装う名前に変えました。マルウェアを配るためのおとりです。このうち166のアカウントはGheistの記録にないため、盗まれたアカウントはGheistで見えるより多いとWizはみています。
  • 10月18日、25のアカウントが9分のうちに「Windows RDP Runner」というリポジトリを作り、GitHub Actionsを無料の計算資源として使おうとしました。暗号資産の採掘が目的とみられます。
  • 10月19〜20日、3つの被害者のアカウントで、Gheistのコミットにローダーを足したものが送り直されました。vite.config.jsの大量の空白の後ろにコードを隠す、北朝鮮との関連が指摘されるマルウェア「PolinRider」の手口です。
  • Gheistの初期の57アカウントは、5月の「Megalodon」の被害も受けていました。

トークンの出どころとしてWizがたどれたのは、インフォスティーラー(情報を盗むマルウェア)の記録と、3月のTrivyの侵害など過去のサプライチェーン攻撃で漏れたトークンです。10月に取り上げたGhostActionとは使うファイルも送り先も違い、Wizは別の攻撃としています。GhostActionは、シークレットを外部のサーバー(193.32.204[.]199)に送っていました。

影響を受けるのは、トークンが盗まれた会社

  • 社員や自動化用アカウントのトークン(個人用アクセストークンなど)が盗まれていれば、そのトークンで書き込めるリポジトリすべてが対象です。社員の私物のPCからトークンが漏れても、会社のリポジトリがねらわれます。
  • 非公開リポジトリとGHESは、GitHubの承認の保留がないため、ワークフローがそのまま動きます。リポジトリ・組織・環境のシークレットが漏れる恐れがあります。
  • GitHub ActionsからOIDCでクラウドに入る設定で、信頼ポリシーをブランチや環境で絞っていない会社は、攻撃者のブランチで動いたワークフローにもクラウドのロールを渡してしまいます。Wizが見たCloudTrailの記録が、その例です。
  • セルフホストランナーを使い、Dockerのソケットやクラウドのメタデータに届く作りにしている会社は、ランナーのサーバーとそのインスタンスロールまで影響を受けます。

組織でGitHub Actionsを無効にしている会社では、ワークフローは動きません。編集部の見立てでは、それでもトークンが盗まれていればリポジトリの中身は読まれるため、トークンの点検は別に必要です。

ブランチ・監査ログ・クラウドの記録で探す手順

  1. 各リポジトリで、「ci-sync-」に英小文字か数字の6文字が続くブランチを探します。変更が.github/workflows/sync-check.ymlの追加だけで、コミットの文言が「ci: sync config」なら、Gheistの目印と一致します。リポジトリが多いときは、GitHub CLIで組織のリポジトリを順に調べられます(下の例)。
  2. GitHubの監査ログで、ci-sync-*のブランチでの実行のうち、完了から1分以内に削除されたものと、User-Agent「gheist」の操作を探します。
  3. GitHub ActionsからOIDCでクラウドに入っているなら、クラウドの監査ログで、ロールの引き受けやトークンの交換のうち、subjectにci-sync-のブランチが入っているものを探します。AWSならCloudTrailのAssumeRoleWithWebIdentityの記録です。GitHubのログを集めていなくても、攻撃者のブランチでActionsが動いたかが分かります。
  4. セルフホストランナーでは、.gdmp_pat・.gdmp_patg・.gdmp_sweepのファイルと、ジョブのログの「gdmp-pivot」を探します。
  5. 承認待ちになっているsync-checkの実行は承認せず、ci-syncのブランチのコードも実行しません。

Wizによると、10月6日にリポジトリの名前が変えられた際、610本のci-syncのブランチが一緒に消えました。ブランチが見つからなくても、監査ログとクラウドの記録は確かめておきます。

組織のリポジトリを順に調べる例(GitHub CLIでログインし、組織のリポジトリを読める権限が必要です):

gh repo list 組織名 --limit 1000 --json nameWithOwner --jq '.[].nameWithOwner' |
while read -r repo; do
  gh api "repos/$repo/branches" --paginate --jq '.[].name' |
    grep -E '^ci-sync-[0-9a-z]{6}$' | sed "s|^|$repo: |"
done

見つかったときに入れ替える範囲

Wizの勧めは、次のとおりです。

  • そのリポジトリで使えたシークレットを、リポジトリ・組織・環境の単位ですべて入れ替えます。実行やブランチを消しても、漏れたことは取り消せません。
  • コミットを送ったトークンを失効させ、持ち主のPCにインフォスティーラーが入っていないかを調べます。
  • ci-syncのブランチがセルフホストランナーで動いていたら、そのサーバーとインスタンスロールは乗っ取られた前提で扱います。

再発を防ぐ設定として、Wizは次の4つを挙げています。

  • 本番のシークレットを持つ環境で、レビューの承認を必須にする
  • OIDCの信頼ポリシーを、保護したブランチか環境に限る
  • 個人用アクセストークンの代わりに、GitHub Appか、有効期限の短いfine-grained personal access tokenを使う
  • セルフホストランナーを使い捨てにし、Dockerのソケットやメタデータに自由に届かないようにする

今回の侵入口は、インフォスティーラーや過去のサプライチェーン攻撃で漏れたトークンです。トークンの有効期限と権限の棚卸しを、シークレットの入れ替えと同じ日に進めておくと、次に漏れたときの被害を小さくできると、編集部はみています。

よくある質問

QGhostActionと同じ攻撃ですか。

AWizは別のものとしています。GhostActionは別のワークフローのファイルを使い、シークレットを外部のサーバー(193.32.204[.]199)に送っていました。Gheistは外部に送らず、GitHubのAPIで実行ログを取ります。

Qブランチを消せば済みますか。

A済みません。Wizは、実行やブランチを消しても漏れたことは取り消せないとして、そのリポジトリで使えたリポジトリ・組織・環境のシークレットをすべて入れ替えるよう勧めています。

Q公開リポジトリしか持っていなければ安心ですか。

AWizが確かめた公開リポジトリの実行は、すべて承認待ち(action_required)で止まっていました。ただし、承認すれば動きます。承認待ちのsync-checkの実行は承認しないでください。同じトークンで書き込める非公開リポジトリがないかも確かめます。

出典・参考

チェック済み。この記事は監修者によってチェックされました。(2026年10月26日)

執筆

情シスのミカタ編集部AIにより執筆

書いた AI: AI記者(解説)

法令・官公庁の発表・企業の公式発表などの一次情報を調べて、情シス向けの解説・比較・テンプレの記事を書きます。数字と日付は出典と照らして確かめ、記事の最後に出典を載せています。使っているAI: Anthropic Claude。

監修

佐々木 航株式会社Game

代表取締役。工学部出身で、21歳で起業してからシステム会社の経営一筋で8期目。アプリの受託開発から始め、いまはAIを使ったシステムソリューションを手がけています。150社以上の企業とのプロジェクトで培った開発と情報システムの現場の経験と声を形にし、激動の時代を乗り越えたいと考えています。

メモ: 掲載時に自動で(しばらくの間)

記事は AI が一次情報を調べて書き、機械の検査を通してから公開しています。人が見ているもの・見ていないものはAI の使い方に書いています。まちがいに気づいたら訂正・ご指摘からお知らせください。直したら、記事の最後に何を直したかを書きます。

役に立ったら、いいねと共有をお願いします