git push経路の内部プロトコル欠陥だけでバックエンド上でリモートコード実行が可能であり、GitHub.com はすでに緩和済みだが、GHES にはパッチ適用が必要- ユーザー制御入力である push option がそのまま
X-Statヘッダーに入り、セミコロン 1 つで新しいフィールドを注入でき、同じキーの後続値が先行値を上書きする last-write-wins の挙動が悪用された - 注入可能なフィールドのうち
rails_env、custom_hooks_dir、repo_pre_receive_hooksを組み合わせるとサンドボックスを回避し、攻撃者が指定したパスのフックをgitユーザー権限で実行できた - 同じメカニズムで GitHub.com の enterprise mode フラグ まで注入でき、shared storage node でコード実行が確認され、そのノード上の他ユーザーや組織のリポジトリまで読み取れる状態につながった
- 異なるサービスが共有フォーマットを信頼する マルチサービスアーキテクチャ では、入力サニタイズ不備、非本番実行経路、パス検証漏れが組み合わさると重大な脆弱性に発展しうることを示している
即時対応と影響範囲
- GitHub.com ではこの問題はすでに緩和済みで、追加対応は不要
- GitHub Enterprise Server は即時対応が必要で、
CVE-2026-3854の修正を含む GHES 3.19.3 以降 へアップグレードする必要がある - 脆弱なバージョン範囲は GHES 3.19.1 以下 で、修正版として
3.14.24,3.15.19,3.16.15,3.17.12,3.18.6,3.19.3が提示されている - 執筆時点で GHES インスタンスの 88% がまだ脆弱な状態だった
- GitHub の追加技術情報と復旧手順は GitHub Security Blog で確認できる
- Wiz の顧客は Wiz Threat Center の事前構築済みクエリ により脆弱な GHES インスタンス を特定できる
調査の背景とアプローチ
- GitHub の内部 git インフラは、すべての
git pushを処理する経路であり、複数の内部サービスが異なるプログラミング言語で書かれている - このような マルチサービス構造 では、各コンポーネントが共有データをどのようにパースし信頼するかの差異が脆弱性につながりうる
- これまでは、このパイプラインを構成する大量の コンパイル済みブラックボックスバイナリ を抽出して監査するには、過大な時間と手作業が必要だった
- AI 強化ツール と
IDA MCPベースの自動リバースエンジニアリングにより、コンパイル済みバイナリを迅速に解析し、内部プロトコルを再構成できた - その過程で、ユーザー入力がパイプライン全体を通じてサーバー動作に影響する箇所を体系的に追跡し、入力フロー全体の 根本的欠陥 を突き止めた
内部アーキテクチャと信頼境界
git pushが SSH で入ると、リクエストはbabeld、gitauth、gitrpcd、そして pre-receive hook の順に流れるbabeldはすべての git 操作の入口として SSH 接続を受け取り、認証はgitauthに渡すgitauthはユーザー資格情報とリポジトリへの push 権限を確認し、ファイルサイズ制限やブランチ名ルールなどのセキュリティポリシーを返すbabeldはこの応答に基づいて、セキュリティメタデータ を含む内部X-Statヘッダーを構成するgitrpcdはX-Statヘッダーを受け取って後続プロセス環境を設定し、独自の認証なしにbabeldを全面的に信頼している- pre-receive hook は push を受け入れる前に、ファイルサイズ制限、ブランチ名ルール、LFS 整合性、管理者定義のカスタムフックを検査する
- 中核となる結合点は、
;区切りのkey=valueペアを含む X-Stat ヘッダー だった - 内部サービスは
X-Statを;基準で分割してマップに格納し、同じキーが 2 回出ると後続値が先行値を上書きする last-write-wins ルールに従う babeldはgit push -oで渡された push options をpush_option_0,push_option_1,push_option_countのようなフィールドとしてX-Statに一緒に入れる
脆弱性の原因: X-Stat フィールド注入
babeldはユーザー制御入力である push option 値 をX-Statヘッダーにコピーする際、セミコロンをサニタイズしていなかった;はX-Statのフィールド区切り文字であるため、push option 内のセミコロン 1 つで本来のフィールドを抜け出し、攻撃者制御フィールド を新たに作成できた- たとえば
push_option_0内にlarge_blob_rejection_enabled=bool:falseを注入すると、先に設定されていたbool:trueが後続値で上書きされる - この挙動はバイナリ解析と実際の GHES インスタンスでの パケットキャプチャ の両方で確認された
- リバースエンジニアリングと wire-level 解析を組み合わせ、注入可能な
X-Statフィールドをマッピングした - 特にセキュリティ上重要なフィールドとして
rails_env,custom_hooks_dir,repo_pre_receive_hooks,large_blob_rejection_enabled,reject_sha_like_refs,user_operator_modeが確認された - このうち
rails_env、custom_hooks_dir、repo_pre_receive_hooksの 3 フィールドがリモートコード実行につながる核心だった
GHES で RCE に至る経路
- GHES は push を受け入れる前に実行される custom pre-receive hooks をサポートしている
- pre-receive バイナリには、
X-Statのrails_env値だけで分岐する 2 つの実行経路 があった - 値が
productionならフックをサンドボックス内で実行し、それ以外の値ならサンドボックスや隔離なしでgitサービスユーザー権限のまま直接実行する - したがって
rails_envに非本番値を注入すると、サンドボックス回避 が可能になる - 続いて
custom_hooks_dirを注入すると、フックスクリプトを探す既定ディレクトリを攻撃者が制御できるようになる - 最後に
repo_pre_receive_hooksにパストラバーサルを含むフック定義を注入すると、バイナリのパス解決が攻撃者制御ディレクトリとトラバーサルペイロードを結合し、ファイルシステム上の任意パス を指すようになる - 非本番実行経路は、このように解決されたパスを引数なし、サンドボックスなし、
gitサービスユーザーとして直接実行する - 実際の検証では
git push1 回でuid=500(git)の出力が返り、gitユーザー権限での RCE が確認された - この権限により、GHES インスタンスのファイルシステム読み書きと内部サービス設定の可視性を含む 全面的な制御権 を取得できた
GitHub.com への拡張とクロステナント露出
- 同じエクスプロイトチェーンを GitHub.com リポジトリに適用した当初は、push 自体は成功したが custom hooks は実行されなかった
user_operator_mode=bool:trueを注入して両プラットフォームのデバッグ出力を比較した結果、GitHub.com では custom hooks のコード経路に到達していないことが分かった- 追加のリバースエンジニアリングにより、サーバーの enterprise mode 動作有無を制御するブールフラグが
X-Statヘッダーに存在することが確認された - GHES ではこのフラグが既定で true のため custom hooks 経路が常に有効であり、GitHub.com では既定値が false のため通常状態ではその経路に到達しない
- このフラグも同じメカニズムで注入できたため、フィールドを 1 つ追加注入することで GitHub.com でも完全な エクスプロイトチェーン が機能した
- その後、GitHub.com インフラ内部で
hostname実行結果が返され、GitHub.com RCE が確認された - GitHub.com は マルチテナントプラットフォーム であり、複数ユーザーや組織のリポジトリが共有バックエンドインフラに保存されている
- コード実行が発生した場所は shared storage node で、ここで
gitユーザーはそのノード上のすべてのリポジトリ操作を処理するための広範なファイルシステム権限を持つ - このユーザーが侵害されると、そのノード上の他組織や他ユーザーのリポジトリも、所有者に関係なく読み取れるようになる
- 侵害された 2 つのノードでアクセス可能なリポジトリのインデックスエントリを列挙したところ、各ノードに 数百万件のエントリ があり、他ユーザーや他組織のリポジトリが含まれていた
- 他テナントの実際のリポジトリ内容にはアクセスせず、自身のテストアカウントのみを用いて、
gitユーザーのファイルシステム権限が ノード内のすべてのリポジトリ読み取り を許していることを検証した
主要な教訓と公開日程
git push1 回だけでも、内部プロトコル欠陥を悪用してバックエンドインフラ上で リモートコード実行 が可能だった- 異なる言語で書かれた複数サービスが共有内部プロトコルでデータをやり取りする場合、各サービスの 信頼前提 そのものが攻撃面になる
- 今回のチェーンでは、あるサービスが push option 値をそのまま挿入し、別のサービスが
X-Statの全フィールドを信頼し、pre-receive hook は本番環境でrails_envがproductionであると仮定していた - 本番バイナリ内の 非本番コード経路、フックスクリプトに対するパストラバーサル検証の欠如、区切り文字ベースのプロトコルにおける入力サニタイズ不備は、他のコードベースにも現れうるパターンである
- マルチサービスアーキテクチャを運用するチームは、とりわけセキュリティセンシティブな設定が共有データフォーマットから導出される場合、ユーザー制御入力が 内部プロトコル に沿ってどう流れるかを点検する必要がある
- 今回の研究では、
IDA MCPを含む AI 強化リバースエンジニアリング ツールが、コンパイル済みバイナリ解析と内部プロトコル再構成を迅速に可能にした - こうしたツールが成熟するほど、深い クロスコンポーネント解析 を必要とする脆弱性群を見つける上で、より重要な役割を果たすとみられる
- 公開日程としては、
2026-03-04に X-Stat push option 注入脆弱性を発見し、同日GHES 3.19.1で RCE を確認して GitHub に報告、GitHub.com 修正も同日にデプロイされた 2026-03-10には CVE-2026-3854 とCVSS 8.7が割り当てられ、GHES パッチが公開された2026-04-28に 公開 された
1件のコメント
Hacker Newsの反応
内部の認証サービスが設定するセキュリティ上重要なヘッダーに、
エンドユーザーが
git push -oで入れた任意の文字列まで一緒に入るようになっていたわけだ後からなら何とでも言えるとはいえ、これはさすがにひどすぎる
AI支援リバースエンジニアリングというやり方は、今のLLMエージェントの強みをよく示している
コードを大量に学習したモデルなら、複雑なシステム内部を理解する速度を大幅に引き上げられる
セキュリティ研究はたいてい 1) 複雑な内部動作を把握することと 2) その中で脆弱性を見つけることが重なっていて、
ときには本当の内部メカニズムさえ見えれば、脆弱性そのものは案外すぐ見えることもある
CVE-2026-3854は、内部を知ってもすぐ obvious な類型ではなかったが、
もっと伝統的だったり近づきやすい攻撃面に露出していたなら、このコマンドインジェクションはすぐ発見されていただろうと思う
ただ最近はその流れが少し乱れたか、あるいはC++の文法の複雑さから生まれる dev/vendor lock-in を守りたい側によって意図的に妨げられているようにも感じる
Wizで働いている人がいるのかと思うくらい、成果物はかなり良さそうに見える
製品も極端な成長と機能肥大を経験しながら、まだかなりよく持ちこたえているし、
セキュリティチームも本当に面白いものをよく見つけてくる
osv-scannerとtrivyを回すカスタムパイプラインしか使っていないなのにCLIでDCを照会して資格情報をリセットするような、少し怪しい作業には静かなままで拍子抜けする
babeldがpushリクエストを転送するとき、内部リクエストのX-Statヘッダーにpush optionsを入れていて、その値はユーザーが
git push -oで入れる任意の文字列だところがセミコロンを sanitize しないまま値をそのままコピーしたため、
;がX-Statフィールドの区切り文字なので、本来のフィールドから抜け出して攻撃者が新しいフィールドを作れてしまった本当に最も単純なミスをそのままやってしまったレベルで、木の実が低すぎて地中に埋まっているくらいに見える
まだ悪用される前に見つかった脆弱性なのに、
BREAKING、unauthorized access、millions of repositoriesのような表現でいたずらに恐怖を煽る必要があるのかと思う
https://x.com/wiz_io/status/2049153209982140718
GitHubは国家支援の攻撃者ではなく、Wizのファジングに引っかかっただけなので運が良かったとも言える
**GHESインスタンスの88%**が、7週間前に出た致命的なセキュリティパッチをまだ適用していないというのは、かなり深刻に見える
https://docs.github.com/en/enterprise-server@3.19/admin/release-notes#3.19.3
パッチレベルのリリースを1つ適用するだけでも数時間のダウンタイムが必要で、
サポートされたHAアップグレード方法もないため、真面目な顧客でさえ最新バージョンにすぐ追随しにくい
不満を言うとみんな GitHub Enterprise Cloud に移れと言うが、
今の時代にそれをすんなり選ぶ人がどれだけいるかも疑問だ
とはいえGHESには、github.comの日々の障害では止まらないという利点はある
運用影響の少ない日程を確保してアップグレードしようとしているのだろう
ただし公開インスタンスなら直ちに更新すべきだ
記事に出ている情報と公開されているGitHub Enterpriseのソースだけでも、再現手順を組み立てるのは難しくなさそうだ
予定通りに進めて何も起きないことを祈ることもできるが、たいていは後者が選ばれる
オンプレミス製品が年1回しか更新されなくても不思議ではない
データ規模の大きいエンタープライズソフトウェアは、些細なことで導入環境が壊れて運用チームがロールバックするのが珍しくなかった
昔のSharePointアップグレードは、ほとんどサイコロを振るようなものだった
今回もWizの大きな成果であり、
AIツールがREや侵入経路の発見をどれほど後押しするかを示す転換点のように感じる
セキュリティは結局、security through obscurityに頼るべきではないというデータポイントがまた1つ積み上がったわけだ
みんなGitHubを代替しようと言うが、では何を使うのかという悩みが残る
GitHubほどのところでさえ今になってRCEが出るのだから、他の代替がもっと良いと簡単には断言しにくい
https://news.ycombinator.com/item?id=46961345
https://news.ycombinator.com/item?id=47712656
GitHubは無料CIを使っている間だけミラーとして活用するやり方だろう
シークレットは別の secret-hosting provider に任せればいい
Forgejoがここまで反応が速く、GitHubがここまで遅くなったというのが今でも信じられない
内部向けはprivateなForgejoインスタンスに置き、公開用はGitHubに載せつつForgejoへミラーしている
Forgejoは実質シングルバイナリで設定も簡単なので驚いたし、
内部サービスはすべてForgejoを見るようにしてあるので、GitHubを離れることになっても摩擦が少ない
オールインワンのDockerイメージとGitLab runnerが数個あれば、小規模から中規模のチームには十分で、
本当に必要でなければKubernetes版まで複雑にする理由はない
ソースコードからAIが脆弱性を見つけるのも印象的だったが、
バイナリ実行ファイルからまでやってのけるのは本当に驚きだ
良い意味でも悪い意味でも潜在力は非常に大きい
そしてまたしても、データを命令として扱ってはいけないという教訓が示された
ユーザー入力はすべて sanitize しなければならない
だから source-to-source や text-to-source に強いのはおなじみの話で、
asm版を理解するのにも適しているのは、そこまで意外なことではないのかもしれない
それでも印象的であることに変わりはない
これが実際に悪用されたかどうかを判定できるのか気になる
HTTP/git protocol のログで悪用の有無自体はある程度確認できるだろうが、
実際に何へアクセスし、誰が行ったかまでは残っていない可能性が高い
エクスプロイトがgitサーバー上で独立実行できたなら、定義上ロギングを回避できたはずだからだ