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. 1

    issue を立てる

    誰でも起動できるラベル付けのワークフローが動く

  2. 2

    本文がプロンプトに入る

    issue のタイトルと本文が、そのまま Codex への指示に埋め込まれる

  3. 3

    サンドボックスの中で実行

    隠した指示で、Codex にスクリプトを動かさせる

  4. 4

    サンドボックスの外へ

    ランナーのプロセスのメモリから、ワークフローのトークンを読む

  5. 5

    キャッシュを汚す

    権限の強い別のワークフローが読む Actions のキャッシュを書き換える

  6. 6

    npm の公開経路へ

    OIDC トークンを要求させ、公式パッケージを公開できる状態に近づく

出典: Depi「Backdooring the next release of Codex through GitHub Action pipeline exploit chaining」(2026-11-11)。攻撃の手順の細部は省略

まず、自分のリポジトリで「誰でも起動できる 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月まで残った

  1. 2025.10

    ワークフローを追加

    issue を立てると Codex がラベルを提案する

  2. 2026.4

    codex-action v1.7 に固定

    allow-users: "*"。サンドボックスは既定の workspace-write

  3. 5/13

    ワークフローを削除

    コミットの題は「Deprecate issue labeler」

  4. 5/15

    読み取り専用で戻す

    sandbox: read-only を追加。誰でも起動できる設定は残る

  5. 5/29

    環境を分ける

    environment: issue-triage を追加

  6. 11/11

    エージェントをやめる

    ツールなしの API 呼び出しと、厳密な JSON の出力に置き換え

出典: openai/codex の git 履歴(.github/workflows/issue-labeler.yml)と codex-action v1.7 の action.yml。日付はコミットの日付(UTC)
日付(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 の形に固定
  • 返ったラベルを既知の一覧で確かめる
  • ラベルを付ける処理は別のジョブで行う
出典: openai/codex のコミット 14e039906c(.github/scripts/issue_labeler.py と issue-labeler.yml)

置き換え後の .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)