世界を動かす技術を、日本語で。

Nixエコシステムの攻略

概要

  • nixpkgs で発見された重大な GitHub Actions の脆弱性についての解説
  • pull_request_target イベントの危険性と実際の攻撃手法
  • コマンドインジェクションローカルファイルインクルージョン の具体例
  • 修正対応と セキュリティ教訓
  • 今後の 安全な運用方法 と参考リソース紹介

NixpkgsのGitHub Actions脆弱性発見と経緯

  • NixCon で発表された、nixpkgsに存在した深刻な 脆弱性 の発見事例
  • 発見者は lexi 氏と筆者、調査から報告・修正まで約1日で完了
  • GitHub Actions の設定ミスを悪用した サプライチェーン攻撃 の危険性
  • pull_request_target イベントが標的、デフォルトで リポジトリ書き込み権限シークレットアクセス を有効化
  • GitHub公式ドキュメント でもpull_request_targetの危険性を警告

pull_request_targetの危険性

  • pull_request_target は、 フォークからのPR でも 書き込み権限シークレット にアクセス可能
  • 通常のpull_requestイベントとは異なり、 悪意あるコード の混入リスクが高まる
  • nixpkgs 内でpull_request_targetを利用したワークフローを調査、14個を発見
    • 一部は安全な実装(例:信頼できるアクションのみ利用)

コマンドインジェクション脆弱性(EditorConfigチェック)

  • EditorConfigルール 検証用ワークフローで コマンドインジェクション を発見
    • PRで変更されたファイルリストを取得し、 xargs でeditorconfig-checkerに渡す処理
  • xargs のmanページにも「安全に使えない」と明記
  • 攻撃例:--helpというファイル名をPRに追加→editorconfig-checkerのヘルプが表示される
  • 任意コマンド実行 の可能性、さらなる調査で深刻な被害も想定

ローカルファイルインクルージョン脆弱性(CODEOWNERSチェック)

  • CODEOWNERSファイル 検証ワークフローで ローカルファイルインクルージョン を発見
    • PR内のOWNERSファイルを シンボリックリンク で任意ファイルに差し替え可能
  • 攻撃例:OWNERSを GitHub Actionsの認証情報ファイル へのリンクに変更
    • バリデータがファイルを読み込み、エラーメッセージとして トークン情報 をログ出力
  • 結果: nixpkgsリポジトリ への 直接push権限 を取得、通常のレビュー手順をバイパス可能

修正対応とセキュリティ教訓

  • nixpkgsメンテナー(infinisil氏) による即時対応
    • 脆弱なワークフローの 無効化安全な実装 への修正
    • pull_request_targetの ブランチ指定の落とし穴 にも注意し、ワークフロー名を変更
  • 重要な教訓
    • 未信頼データシークレット情報 の混在を避ける
    • 最小限の権限 のみ許可
    • 公式ドキュメント で権限仕様を必ず確認
    • 組織全体で不審なGitHub Actionsがある場合、 一括無効化 も検討
      • Settings→Actions→General→Policiesで「All repositories」を「Disable」に設定

まとめ・参考リソース

  • 脆弱性発見から修正まで1日 で対応、nixpkgs全体のセキュリティを守る
  • pull_request_target 利用時は特に注意が必要
  • 関連資料・発表
  • GitHub Actions 運用時は常に 安全性 を最優先に
  • みなさんも 安全なCI/CD運用 を心がけてください

Hackerたちの意見

まあ「いい」ニュースは、OpenBSDとNetBSDはまだCVSを使ってるってことだね。パッケージに関してもそう。だから、これらのシステムではうまくいかないよ。FreeBSDについてはわからないけど。セキュリティは隠蔽によるものだね :) でも、これらのプロジェクトがgitに移行しようとしてるっていうドキュメントを見たことがあるから、実際にどうなるか見てみよう。OpenBSDの場合は、got(1)をベースにするみたい。

はっきりさせておくけど、君の言ってることは正しい。でも、これはgitの脆弱性じゃなくて、GitHub Actionsの脆弱性なんだ。つまり、BSDはCVSで守られているのは、GitHubがCVSを使ってないから。もしgitやGitHubを使っていても、GitHub Actionsを使ってCI/CDをやらなければ影響は受けないよ。

これはgitの問題じゃなくて、GitHubの問題だし、私が見る限りGitHub Actionsに特有のものだね。

彼らは貢献を受け入れるのにメールを使ってないの? なかなかセキュリティ的に厄介なことになりそうだね、なりすましの観点から。

これは、pull_request_targetが根本的に不安定である理由の良い例だし、GitHubは(私の意見では)これを完全に削除すべきだと思う。一般的な考えでは、pull_request_targetは「安全」とされてるけど、ブランチ制御されたコードがジョブのコンテキストで実行されない限り、こういう引数の注入やローカルファイルのインクルードの脆弱性があることを示してる。今のところ、pull_request_targetの正当な使い方は、サードパーティのPRにラベルを付けたり、自動コメントを残したりすることだけだよ。でも、これらのアクションがリポジトリにデフォルトで書き込み権限を持つ必要はない。GitHubは、そういう操作を可能にする細かいトークンや(さらに良いのは)使い捨てトークンを発行できるはずだよ。(これが、zizmorがpull_request_targetや他の危険なトリガーの使用を一律にフラグ付けする理由だよ[1])。 [1]: https://docs.zizmor.sh/audits/#dangerous-triggers

GitHubがこれについてこう言ってるよ: > このイベントは、プルリクエストのマージコミットのコンテキストではなく、プルリクエストのベースのコンテキストで実行されます。これにより、リポジトリを変更したり、ワークフローで使用する秘密を盗んだりする可能性のあるプルリクエストの先頭からの危険なコードの実行が防がれます。秘密が簡単に流出したことを考えると、これは滑稽だね。

それには同意するけど…フォークを許可しない組織には使い道があるんだ。一部のツールはGitHubの外でマージを行うから、マージの観点からクリーンにならないPRを許可してるんだ。これだとpull_requestのワークフローはトリガーされないよ。だってpull_requestはクリーンなマージが必要だからね。そういう場合、pull_request_targetが文字通り唯一の選択肢になる。GitHubがクリーンなマージがないPRで自動化を実行できる設定をデフォルトでオフにして、リンター専用に使えるようにしてくれればいいんだけどね。それが実現するまで、pull_request_targetがその制限を回避する唯一の方法だよ。私や他のSecDevOpsエンジニアにとっては悲しいけどね。注意: これらの外部ツールを使うと、GitHubで手動でマージすることは絶対にできないから、全体が壊れちゃうよ。本当に楽しくないことになる。

プライベートリポジトリ内ではpull_request_targetを使ってるんだ。1. それはメインに存在するワークフローを実行するから、改ざんされていないテストスイートが実行できる面を提供するし、2. OIDC対応システムでの非常に細かいアクセス制御に使える決定論的なjob_workflow_refをjwtのサブクレームに提供するからね。

プルリクエストやマージリクエストのためのCI/CDアクションは本当に厄介だよ。開発者がテストや検証のステップを書くとき、ほとんどが「これは自分のGitHub/GitLabアカウントのコンテキストで動いてるコードだ」って考えてるんだ。これは自分やチームメンバーが行ったコミットには当てはまるけど、プルリクエストでは実際に信頼できないコードが実行されるんだ。この違いを100%正確に理解するのは結構難しいよ。基本的なケースでは、テストスイートやリンターを実行するだけならそれほど悪くないけど、自分のインフラと統合しなきゃいけないエッジケースにぶつかると、すぐに厄介なことになるよ。

プルリクエストでCI/CDが動くこと自体が問題だとは思わないけど、GitHubには非常に似たトリガーが2つあるのが問題なんだ(pull_requestpull_request_target)。そのうちの1つはほぼ完全に安全で(使い方を間違えない限り)、もう1つはほぼ完全に危険なんだ(安全に使うのはほぼ不可能)。さらに悪いことに、GitHubはPRに対する特定の操作(自動ラベリングや自動コメントの追加)を、非常に危険なバージョン(pull_request_target)を使わない限り完全に不可能にしてしまった。だから、これはインセンティブによる不安定さのケースなんだ。人々はサードパーティのPRに対して合理的な操作をしたいと思ってるけど、GitHub Actionsが提供する唯一のメカニズムは足元を撃つようなものなんだ。

この記事にはもっと広い影響がある大きな足元を撃つ問題があるよ。> でも、さらに悪化する。ワークフローが私たちのPRコードをチェックアウトしていたので、OWNERSファイルをランナー上の任意のファイルへのシンボリックリンクに置き換えることができた。例えば、GitHub Actionsの認証情報ファイルとかね。だから、gitはソフトリンクのコミットを許可してる。だから、上記の問題はほぼすべてのワークフローに影響を与える可能性があるんだ。

xargsを安全に使うことはできないんだって。えっと…それはかなり文脈から外れてるね。その文は続きがあるんだ。cat "$HOME/changed_files" | xargs -r editorconfig-checker --ってやれば、この特定の問題は解決するよ。

うん、その文がmanページにある理由はここには当てはまらないと思う。でも、一般的な感覚は正しいよね。すべてのプログラムが--を引数と入力の区切りとしてサポートしてるわけじゃないから、多くのxargsの呼び出しは、引数の注入一つで任意のコード実行に繋がる可能性があるんだ。(これは伝統的には問題にならないけど、要はコードを実行するためのものだからね。だから、xargsのせいというよりは、特権コンテキストを跨いでツールが再利用されることの永遠の問題だね。)

でも、これはxssを避けるためにhtmlで値を表示するたびに{escapeHtml(value)}を追加するようなもんだよね。どこでも安全な使い方を選ばなきゃいけないなら、それは安全じゃないやり方だと思う。

こんなに長い間コンピュータシステムを設計してきたのに、今でもモダンなワークフローが信頼されたプログラムに対して、短命のベアラートークンを発行するように設計されてるのは恥ずかしいと思う。もしGitHubアクションフレームワークが特権のUnixソケットやssh-agentへのアクセスを与えていたら、この種の脆弱性を悪用するのはかなり難しくなったはずだよ。

その通り!ベアラートークンは署名に基づくスキームに置き換えるべきで、プライベートキーは絶対に直接公開しちゃダメだよ(公開されたら、ベアラートークンと何も変わらないからね)。署名エージェントはその役割を果たすんだ。GitHubのAPIはHTTPに基づいてるけど、署名エージェントとの相互TLS認証があれば十分だと思う。

SPIFFEの標準はそんな感じのことをやってるよ。でも、誰も実際にはセキュリティに興味がないから、誰も使ってないんだ。業界全体が結局は詐欺みたいなもんだよね。

xargsのmanページを読んだことがあるなら、この警告が見えるはず: >> xargsを安全に使うことはできない。しかし、この警告に関連するセキュリティの問題は、ここには当てはまらないよ。ここでの問題は、コマンドの最後に--を使うことで回避できるんだ。

時間が経つにつれて、サプライチェーン攻撃についてますます心配になってきた。これは「これが原因で仕事を失うかも」とか「NixOSやCI/CD、Nodeなどが新しい攻撃ベクターを生んでる」って視点じゃなくて、もっと哲学的な観点からなんだ。頼れば頼るほど、問題が増えていくのは避けられないからね。特に複雑なことを考えてるわけじゃなくて、VSCodeやEmacs、Nix、Vim、Firefox、JavaScript、Node、それに無限のプラグインや依存関係を使うだけでも、もう絡まり合った混乱に感じる。恥ずかしいことに、これが原因で紙と一番シンプルでバカみたいな技術を使う方向に進んでるんだ—拡張機能もプラグインもなしで、ただコントロールやセキュリティを感じたいだけなんだよね。完全に理にかなってるわけじゃないって分かってるけど、現代の技術に対する失望感がどんどん大きくなっていくのをどうしても振り払えない。もうこれ以上の複雑さには耐えられないよ。