「コードを書ける」と「コードを動かせる」は、まったく別の話のはずだった——そのはずが、Gitea では書くだけで動かせてしまっていた。
「書いた原稿が、いつの間にか印刷機を動かしていた」
今週パッチが公開された CVE-2026-60004(CVSS スコア: 9.x)は、自己ホスト型 Git プラットフォーム Gitea の重大な脆弱性だ。リポジトリへの通常の書き込みアクセスを持つユーザーが、細工したパッチ(変更差分ファイル)を送り込むことで、Git フックを仕込むことができた。
Git フックとは、「git push」や「git commit」などの操作が行われたタイミングで自動的に実行されるシェルスクリプトだ。CI テストの起動や通知送信に広く使われている正規の機能——それが攻撃者の手によって「Gitea サービスアカウント権限でのシェルコマンド実行」に変わってしまう。書き込みアクセスしか持っていないはずのユーザーが、サーバー上で任意のコマンドを root 相当の権限で走らせられた。
sequenceDiagram
participant 攻撃者
participant Gitea
participant Gitフック
participant サーバー
攻撃者->>Gitea: 細工したパッチを送信(書き込み権限のみ)
Note over 攻撃者,Gitea: 通常のコントリビュータ権限で可能
Gitea->>Gitea: パッチ適用・フックを植え付け
Gitea->>Gitフック: 次の git 操作でフック自動起動
Gitフック->>サーバー: シェルコマンド実行(サービスアカウント権限)
Note over Gitフック,サーバー: 任意コード実行が成立
「機能を使って入り込む」という構造が見えているか
今回の本質は、バグで誤作動したわけではなく、設計上の信頼境界の見落としだ。Git フックはリポジトリ管理者向けの機能として存在する。問題は、パッチ経由でフックを植え付けられるパスが検証されていなかった点にある。
「書き込みアクセス」と「フックの制御」が同一視されていた——そう読むと、同じ構造が Gitea 以外のシステムにも潜んでいる可能性が見えてくる。GitHub Actions のワークフローファイル、GitLab CI の設定ファイル、自前の Webhook 設定など、「リポジトリに書けるユーザーが、サーバー側の何かを起動できる構成」はどこにでも存在する。パッチを当てて終わり、ではなく「同じ構造が別の場所にないか」を問う起点として読みたい。
自分のリポジトリ設定に照らし合わせると
Gitea を使っていなくても、次の点は確認する価値がある。
# サーバー上の Git フックを確認する
ls .git/hooks/
# pre-receive, post-receive, update などが予期せず存在しないか
# GitHub Actions の場合:PR 差分でワークフローファイルが変更されていないか確認
git diff main...feature -- .github/workflows/
CI/CD パイプラインで Git フックを活用しているチームは、「誰がそのフックを書けるか」を明文化しているだろうか。コントリビュータ権限を持つメンバー全員がフックの内容を変更できる状態にある場合、それは意図した設計かどうかを一度確かめる価値がある。
あなたのリポジトリで、「書ける」と「動かせる」は明確に分かれているか?
今週のパッチを当てれば Gitea 固有の穴は塞がる。しかし「書き込みアクセスがサーバー側の実行に繋がるパスがないか」という問いは、自分のシステム全体に向けても立てられる。PR を出せる人が、知らずにフックやワークフローを上書きできる構成になっていないだろうか?
参考: New Gitea RCE Lets Repository Writers Plant a Git Hook to Run Shell Commands – The Hacker News