Codex GitHub Actions の攻撃連鎖を、セキュリティ企業 Depi が2026年11月11日に公開した。OpenAI Codex のリポジトリで動いていた issue ラベル付けのワークフローを入口に、公式 npm パッケージ @openai/codex の公開経路まで届く連鎖だ。 issue の本文がそのまま Codex への指示に埋め込まれ、誰でも起動できたことが入口だった。OpenAI は Bugcrowd 経由の報告を受けて修正し、利用者側で当てるパッチはない。本記事は、openai/codex の git の履歴で何がいつ変わったかを確かめ、同じ形が自分のリポジトリにないかを探す手順を示す。
ATTACK CHAINDepi が示した6段の連鎖
issue を1本立てるだけで、npm の公開経路まで届いた
-
1
issue を立てる
誰でも起動できるラベル付けのワークフローが動く
-
2
本文がプロンプトに入る
issue のタイトルと本文が、そのまま Codex への指示に埋め込まれる
-
3
サンドボックスの中で実行
隠した指示で、Codex にスクリプトを動かさせる
-
4
サンドボックスの外へ
ランナーのプロセスのメモリから、ワークフローのトークンを読む
-
5
キャッシュを汚す
権限の強い別のワークフローが読む Actions のキャッシュを書き換える
-
6
npm の公開経路へ
OIDC トークンを要求させ、公式パッケージを公開できる状態に近づく
まず、自分のリポジトリで「誰でも起動できる AI アクション」がないかを探す。リポジトリの最上位で実行する。
git fetch --all --prune
grep -rnE "(allow-users|allowed_non_write_users|allowed_bots):[[:space:]]*[\"']?\*" .github/workflows/
30秒でわかる Codex の GitHub Actions 攻撃連鎖(2026年11月11日の Depi の公開)
- ・入口:issue を立てると動くラベル付けのワークフローが、issue の本文を Codex の指示に埋め込み、誰でも起動できた(allow-users: "*")
- ・到達点:サンドボックスの外、Actions のキャッシュ、OIDC トークンを経て、公式 npm パッケージの公開経路に近づいた
- ・利用者への影響:OpenAI が修正済みで、利用者側のパッチはない。悪意ある版の公開の報告もない
- ・履歴で分かったこと:5月15日にサンドボックスを読み取り専用に。誰でも起動できる設定は11月11日(UTC)の置き換えまで残った
- ・自分のリポジトリ:上の grep で「誰でも起動」を探し、本文の埋め込みとトリガーも点検する
まずやること
・AI アクションを CI に入れている:上の grep を実行し、当たったら起動できる人を絞る。続けて下の「点検」の3本を流す
・@openai/codex を使っているだけ:対応は不要。自動更新のツールには、短い待ち時間を置くことを検討する
・これから AI アクションを入れる:外部の人が起動できるトリガーで、本文を指示に埋め込む形を避ける
GitHub 上の AI エージェントへの指示の仕込みは、コメントを使う GitHubコメントがAIエージェントを乗っ取る:「Comment and Control」攻撃の仕組みと防御策 でも扱った。依存先からの攻撃全体の守り方は サプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説 にまとめている。
Codex GitHub Actions の攻撃連鎖:issue 1本から npm の公開経路まで
Depi の解説によると、連鎖は次のようにつながった。攻撃の再現につながる細部(スクリプトや通信の手順)は省く。
| 段 | 何が起きたか | 効いたはずの守り |
|---|---|---|
| 1. issue を立てる | issues の opened と labeled で起動するワークフローを、外部の人が動かせた |
起動できる人を、書き込み権限のある人に絞る |
| 2. 本文がプロンプトに入る | issue のタイトルと本文を $ の形で指示に埋め込んでいた |
本文を指示に入れない。入れるなら、ツールを持たないモデルに渡す |
| 3. サンドボックスの中で実行 | 定型の指示を閉じたように見せる文と、圧縮して隠したスクリプトで、Codex にコマンドを実行させた | サンドボックスを読み取り専用にする |
| 4. サンドボックスの外へ | ランナーの .NET プロセスが /tmp に作るデバッグ用の通り道を開き、メモリからワークフローのトークンを読んだ |
信頼できない入力を扱うジョブに、長く使えるトークンを置かない |
| 5. キャッシュを汚す | 得たトークンで、権限の強い rust-ci.yml が読む Actions のキャッシュを書き換えた |
権限の強いワークフローは、信頼できない側と同じキャッシュを読まない |
| 6. npm の公開経路へ | リリースの削除などをきっかけに動く罠のワークフローで、id-token: write の OIDC トークンを要求させる経路を示した |
公開のワークフローを分け、トリガーと承認を絞る |
Depi は、キャッシュの汚染に使った手法(Adnan Khan 氏の Cacheract)は、issue コメントや pull_request_target などの危ういトリガーにはもう効かないと注記している。GitHub 側の変更の時期と内容は、本記事では確かめられていない。
Bugcrowd の公開ページでは、この報告の評価は最上位の P1、状態は Resolved(解決済み)、報奨金は1,000ドル、ページの公開日は2026年9月29日となっている。Depi は、OpenAI がすぐに修正を出し、報告はなお評価中だと書いている。
Codex GitHub Actions の修正の時系列:変更履歴で確かめる
ワークフローの定義ファイル .github/workflows/issue-labeler.yml の履歴を、openai/codex の git から取り出して比べた。日付はコミットの日付(UTC)だ。公表日は Bugcrowd のページが2026年9月29日、Depi の解説が11月11日。
HISTORYissue-labeler.yml の変更履歴
誰でも起動できる設定は11月まで残った
-
2025.10
ワークフローを追加
issue を立てると Codex がラベルを提案する
-
2026.4
codex-action v1.7 に固定
allow-users: "*"。サンドボックスは既定の workspace-write
-
5/13
ワークフローを削除
コミットの題は「Deprecate issue labeler」
-
5/15
読み取り専用で戻す
sandbox: read-only を追加。誰でも起動できる設定は残る
-
5/29
環境を分ける
environment: issue-triage を追加
-
11/11
エージェントをやめる
ツールなしの API 呼び出しと、厳密な JSON の出力に置き換え
| 日付(UTC) | コミット | 起動できる人 | サンドボックス | 本文の扱い |
|---|---|---|---|---|
| 2026-04-25 | 1c3287125f(v1.7 に固定) | 全員(allow-users: "*") |
指定なし=v1.7 の既定の workspace-write |
指示に埋め込む |
| 2026-05-08 | 8bea5d231a | 全員 | 指定なし(workspace-write) |
指示に埋め込む |
| 2026-05-13 | 4fca5c32da「Deprecate issue labeler」 | ワークフローを削除 | — | — |
| 2026-05-15 | 6afe00efda「Workflow updates」 | 全員 | read-only |
指示に埋め込む |
| 2026-05-29 | 20da4c37c5 | 全員。environment: issue-triage を追加 |
read-only |
指示に埋め込む |
| 2026-11-11 | 14e039906c | Codex のアクションを使わない | — | ツールなしの API に渡す |
履歴から分かったことは3つある。
・5月15日に効いたのはサンドボックスだけ:このとき safety-strategy: drop-sudo も書き足されたが、v1.7 の action.yml ではこれが既定値だった。実際に変わったのは、サンドボックスを workspace-write から read-only にしたことだ
・誰でも起動できる設定は11月まで残った:allow-users: "*" と本文の埋め込みは、11月11日の置き換えまでそのままだった
・11月11日に方式ごとやめた:Depi の公開と同じ日(UTC)に、Codex に任せる方式をやめている
5月13日の削除と15日の読み取り専用化が、Depi の報告への修正にあたる可能性はある。ただし、報告日と修正日は Depi も OpenAI も公表しておらず、これは履歴からの推測だ。読み取り専用のサンドボックスでも同じ脱出ができたかも、確かめられていない。
自分のリポジトリの AI ワークフローを点検する
冒頭の grep に加えて、次の2本を流す。どれも読み取りだけで、ファイルを変更しない。
issue・コメント・プルリクエストの本文を、式でそのまま埋め込んでいる箇所を探す。AI への指示だけでなく、シェルの run: に埋め込んでいる箇所も危ない(スクリプトの注入になる)。
grep -rnE "\\$\{\{[[:space:]]*github\.event\.(issue|comment|pull_request|review|discussion)\.(title|body)" .github/workflows/
AI アクションを使うワークフローと、外部の人が起動できるトリガーを持つワークフローを並べる。両方に名前が出るファイルが、重点的に見る対象だ。
grep -rlE "openai/codex-action|anthropics/claude-code-action|google-github-actions/run-gemini-cli" .github/workflows/
grep -rlE "^[[:space:]]*(issues|issue_comment|pull_request_target|discussion|discussion_comment):" .github/workflows/
検体を置いたフォルダと置かないフォルダで試した。検体は、openai/codex の5月8日の版の issue-labeler.yml と、allowed_non_write_users: "*" でコメントの本文を埋め込んだ Claude Code Action のワークフローだ。対照には、11月11日の版と、既定のままの Claude Code Action を置いた。
| コマンド | 検体あり | 直した形だけ |
|---|---|---|
| 誰でも起動(冒頭) | 2件(allow-users: "*"、allowed_non_write_users: "*") |
0件 |
| 本文の埋め込み | 3件(issue のタイトルと本文、コメントの本文) | 0件 |
| AI アクションとトリガーの一覧 | 両方のファイルが両方に出る | 一覧は出る(判定ではなく棚卸し) |
3本目は判定ではなく棚卸しで、直した形でもファイル名は出る。どの grep も、当たらなかったから安全とは言えない。アクションの名前やトリガーを別の書き方にしていれば当たらないし、再利用ワークフローの呼び出し先までは追わない。逆に当たっても、ほかの条件で守られていることがある。当たった箇所は、次の表で見直す。
| 見るところ | 危ない形 | 直し方 |
|---|---|---|
| 起動できる人 | '*' で全員に開く |
書き込み権限のある人だけにする(多くのアクションの既定) |
| 指示に入れるもの | issue・コメントの本文をそのまま埋め込む | 本文を入れない。入れるなら、ツールを持たないモデルに渡す |
| 実行できること | エージェントがコマンドを実行し、ファイルを書ける | 読み取り専用のサンドボックス。決まった仕事ならツールを渡さない |
| ジョブの権限 | contents: write や id-token: write を同じジョブに持つ |
信頼できない入力を扱うジョブは contents: read だけにし、書き込みは別のジョブに分ける |
| キャッシュ | 権限の強いワークフローが、外部から起動できるワークフローと同じキャッシュを読む | キャッシュのキーと範囲を分ける |
主な AI アクションの、起動できる人の既定値は次のとおりだ(2026年11月14日に各リポジトリの action.yml で確認)。
| アクション | 書き込み権限のない人からの起動 | 全員に開く設定 |
|---|---|---|
| openai/codex-action | 既定では不可(allow-users が空) |
allow-users: "*" |
| anthropics/claude-code-action | 既定では不可(allowed_non_write_users が空) |
allowed_non_write_users: "*"。公式は重大なリスクと警告 |
「エージェントにやらせない」設計:ツールなしの API と厳密な出力
OpenAI の直し方は、設定を絞るのではなく、ラベル付けにエージェントを使うのをやめるものだった。
DESIGN直したあとの設計
ラベルを付けるだけなら、エージェントは要らない
11月まで:エージェントに任せる
- issue の本文をプロンプトに埋め込む
- Codex がサンドボックスでコマンドを実行できる
- 誰でも起動できる
- 出力の形はエージェント次第
11月12日から:API を1回呼ぶだけ
- ツールを渡さない(tools: [])
- 出力は厳密な JSON の形に固定
- 返ったラベルを既知の一覧で確かめる
- ラベルを付ける処理は別のジョブで行う
置き換え後の .github/scripts/issue_labeler.py は、OpenAI の Responses API を1回呼ぶだけだ。
・ツールを渡さない:"tools": []。モデルはコマンドを実行できず、ファイルにも触れない
・出力の形を固定する:json_schema を strict で指定し、ラベルの配列だけを返させる
・返った値を確かめる:既知のラベルの一覧にないものは使わない
・権限を分ける:モデルを呼ぶジョブは contents: read。ラベルを付ける issues: write は別のジョブが持つ
issue の本文に指示を仕込まれても、モデルにできるのは決まった形の JSON を返すことだけになる。最悪でも、一覧にあるラベルが間違って付く程度で済む。
この形は、ラベル付け、要約、分類のように、出力の形が決まっている仕事に向く。コードを読んで直す、テストを動かすといった、ツールが要る仕事には使えない。その場合は、外部の人が起動できるトリガーから切り離し、権限とサンドボックスを絞るほうに頼ることになる。
影響範囲と、まだわかっていないこと
| 対象 | 影響 |
|---|---|
| @openai/codex の利用者 | 対応不要(Depi)。悪意ある版の公開の報告はない |
| openai/codex のリポジトリ | 11月11日(UTC)に Codex のアクションの利用をやめた |
| AI アクションを CI に入れているリポジトリ | 同じ形(誰でも起動・本文の埋め込み・書き込みできるサンドボックス)があれば、同種の攻撃の入口になりうる |
まだわかっていない点は次のとおりだ。
・報告日と修正日:Depi も OpenAI も公表していない。5月の変更が修正にあたるかは推測
・本番で試したか:連鎖全体を openai/codex の本番で動かしたのか、別のリポジトリで再現したのかは、Depi の解説から読み切れない
・読み取り専用での成否:5月15日以降の read-only のサンドボックスで、同じ脱出が成り立ったかは不明
・GitHub 側の変更:キャッシュの汚染が危ういトリガーで効かなくなった変更の時期と内容
同じく GitHub の AI ワークフローを入口にした問題は GitHub Agentic Workflows 脆弱性「GitLost」|公開Issueで漏洩する仕組みと対策 にもまとめた。
参照ソース
・Backdooring the next release of Codex through GitHub Action pipeline exploit chaining(Depi・2026-11-11)
・Backdooring the next release of Codex through Github Action Pipeline exploit chaining(Bugcrowd の公開ページ)
・openai/codex の issue-labeler.yml の履歴(GitHub)
・Use the Responses API for issue label suggestions(openai/codex のコミット 14e039906c)
・openai/codex-action の action.yml(GitHub)
・anthropics/claude-code-action のセキュリティの説明(GitHub)





