Ruby の正規表現脆弱性(2026年10月)|影響確認と更新判断

  • URLをコピーしました!
目次

はじめに

2026 年 10 月 23 日、Ruby 公式は正規表現エンジン Onigmo の不具合を修正した Ruby 4.0.9、3.4.12、3.3.13 を公開しました。これらの不具合は、GitLab が 2026 年 10 月に公表した 4 件の CVE(CVE-2026-89078、CVE-2026-93577、CVE-2026-97229、CVE-2026-110264)の原因に関連するもので、GitLab では細工された正規表現によってサーバー上でのリモートコード実行(RCE)につながる可能性が示されています。

一方で、Ruby を使っているすべてのアプリケーションが同じ危険度にあるわけではありません。「GitLab の CVSS 10.0 が自社の Ruby アプリケーションにもそのまま当てはまるのか」「Regexp.timeout を設定していれば十分なのか」「サーバーで ruby -v を確認すれば対応状況がわかるのか」といった点で、判断に迷いやすい状況です。

この記事でわかること
  • GitLab の 4 件の CVE と、Ruby 側で修正された 3 種類の不具合の対応関係
  • 系列別の修正版と、Ruby 4.0.8 では修正が不足する理由
  • 影響を受ける実装の条件と、Regexp.timeout や入力文字数制限で防げない理由
  • 実際にアプリケーションを動かしている Ruby の確認方法と、更新後のチェックリスト
  • GitLab の対策と、独立した Ruby アプリケーションの更新の違い

結論として、影響を受けるのは、攻撃者が制御できる文字列を正規表現としてコンパイルする処理を持つアプリケーションです。開発者が定義した固定の正規表現だけを使うアプリケーションは、Ruby 公式の説明では影響を受けません。該当する処理がある場合は、Ruby 4.0.9 / 3.4.12 / 3.3.13 以降へ更新し、更新できるまでは信頼できない入力から正規表現をコンパイルしないよう機能や入力仕様を見直してください。

Ruby の正規表現エンジン Onigmo で修正された不具合

今回の修正は、正規表現をコンパイルする段階で発生するメモリ破損系の不具合が対象です。4 件の CVE はいずれも GitLab が割り当てたもので、Ruby 側の不具合は 3 種類に整理されています。

GitLab の 4 件の CVE と Ruby 側の不具合の対応

Ruby 公式の発表によると、GitLab は CI 設定内のパターンなど、利用者が指定した正規表現を Regexp.new でコンパイルしています。細工されたパターンをコンパイルする際にメモリが破損し、GitLab サーバー上でのリモートコード実行につながる可能性があることを GitLab が確認しました。各 CVE と Ruby 側の修正、各系列で修正が初めて含まれたリリースは次のとおりです。

GitLab の CVERuby 側の不具合Ruby 4.0Ruby 3.4Ruby 3.3
CVE-2026-89078選択(|)の後でパターンの解析が失敗した際の Double Free4.0.03.4.123.3.13
CVE-2026-93577
CVE-2026-97229
コンパイル後のパターンサイズに関する整数オーバーフロー4.0.83.4.123.3.13
CVE-2026-110264繰り返しを多数含むパターンでの内部 ID のオーバーフロー4.0.93.4.123.3.13

CVE-2026-93577 と CVE-2026-97229 は、Ruby 側では同じ修正(整数オーバーフローの修正)に対応しています。4 件の CVE は、Ruby 側に 4 種類の独立した不具合があることを意味しません。GitLab 側では、CVE-2026-93577 と CVE-2026-89078 が GitLab 19.4.1、CVE-2026-97229 が 19.4.2、CVE-2026-110264 が 19.5.1 などのパッチリリースで修正されています。

Ruby 側に CVE 番号がない理由

Ruby プロジェクトは、今回の修正について Ruby としての CVE 番号を少なくとも現時点では申請していません。そのため、「Ruby に CVE-2026-110264 が発生した」という理解は正確ではなく、GitLab が割り当てた CVE の原因となった Ruby の不具合が修正されたと捉える必要があります。

Ruby 公式は、信頼できない入力から作成した正規表現をコンパイルして使用することを、従来から一般的に安全ではないと考えてきたと説明しています。過去には CVE-2022-28738 や CVE-2024-27282 のように、正規表現のコンパイルに関する問題を総合的な評価のうえで脆弱性として扱った例もあります。一方で、現在の Regexp のドキュメントは、信頼できない正規表現をサービス拒否(DoS)の観点でのみ説明しており、信頼できないパターンのコンパイルをサポート対象の使い方とするかを明示していません。Ruby プロジェクトは、ドキュメントの記載方法や、この種の問題を Ruby の脆弱性として扱うか(CVE を申請するかを含む)を検討するとしています。

Ruby 公式は、当面はセキュリティスキャナーなどで管理する場合に GitLab の CVE 番号を参照するよう案内しています。ただし、各スキャナーが GitLab の CVE と Ruby の修正版を正しく対応付けるかは製品ごとに異なり、検出されないことが影響を受けないことを意味するとは限りません。GitLab の CVSS 10.0 は GitLab での評価であり、一般的な Ruby アプリケーションの危険度をそのまま示すものではありません。

Ruby 脆弱性の影響バージョンと修正版

3 種類の不具合すべてを修正するには、Ruby 4.0.9、3.4.12、3.3.13 以降が必要です。系列ごとに、修正が含まれる時期が異なる点に注意してください。

系列別の修正版と保守状況

次の表のバージョンは、Ruby 公式リリースでの修正状況です。Linux ディストリビューションなどが提供する Ruby パッケージは、独自に修正をバックポートする場合があるため、各ディストリビューションのセキュリティ情報で別途確認してください。

系列保守状況(2026 年 10 月 23 日時点)すべての修正を含む版補足
Ruby 4.0通常メンテナンス4.0.94.0.8 は修正の一部のみ
Ruby 3.4通常メンテナンス3.4.123.4.11 以前は 3 種類とも未修正
Ruby 3.3セキュリティメンテナンス(EOL 予定: 2027 年 3 月 31 日)3.3.13例外的に今回の修正を収録
Ruby 3.2 以前EOL(3.2 は 2026 年 4 月 1 日)提供なし保守対象の系列への移行が必要

Ruby 3.3 はセキュリティメンテナンス期間中で、通常は脆弱性の修正のみが提供されます。Ruby 公式は、GitLab がこれらの修正に依存する問題へ CVE を割り当てたことから、3.3.13 に例外として今回の修正を含めたと説明しています。なお、Ruby 3.3.13 には、既定の gem である resolv を 0.3.2 に更新する CVE-2026-80212 と CVE-2026-80213 の修正も含まれています。

Ruby 3.2 以前の系列は ruby-core チームのサポートが終了しており、今回の修正版は提供されていません。該当する処理を持つアプリケーションでは、信頼できない入力から正規表現をコンパイルしない対策を優先しつつ、保守対象の系列への移行を計画してください。

Ruby 4.0.8 では不十分な理由

Ruby 4.0.8 は 2026 年 10 月 22 日に定例のバグ修正リリースとして公開され、整数オーバーフロー(CVE-2026-93577 と CVE-2026-97229 に対応)の修正を含みます。Double Free(CVE-2026-89078 に対応)の修正は 4.0.0 から含まれています。しかし、内部 ID のオーバーフロー(CVE-2026-110264 に対応)の修正は 4.0.9 で初めて含まれました。

4.0.8 は前日に公開されたばかりのため、すでに 4.0.8 へ更新した環境で「最新版に更新済み」と判断しやすい点に注意が必要です。Ruby 4.0 系列で外部入力を正規表現としてコンパイルする処理がある環境は、4.0.8 へ更新済みでも 4.0.9 への再更新を優先してください。該当する処理がない環境は、通常の更新計画の中で 4.0.9 以降へ更新することをおすすめします。

影響を受ける Ruby アプリケーションの条件

参考: Ruby 公式「Regexp compilation fixes related to GitLab’s CVE-2026-89078, CVE-2026-93577, CVE-2026-97229 and CVE-2026-110264」
“Applications that only use regular expressions written by their own developers are not affected.”
(開発者自身が記述した正規表現だけを使用するアプリケーションは影響を受けない)
https://www.ruby-lang.org/en/news/2026/10/23/regexp-fixes-for-gitlab-cves/

判断の中心は、外部から渡された文字列が「正規表現の構文」として解釈され、コンパイルされるかです。正規表現を使っているかどうかや、Ruby on Rails を使っているかどうかだけでは判断できません。

外部入力を正規表現としてコンパイルする処理

Ruby 公式は、攻撃者が制御できる文字列から正規表現をコンパイルする場合に限り不具合へ到達すると説明しています。例として挙げられているのは、Regexp.new、Regexp.union、Regexp.compile へ文字列を渡す処理と、/#{input}/ のように正規表現リテラルへ文字列を展開する処理です。なお、Regexp.compile は Regexp.new の別名です。

次のように、正規表現のパターンを開発者がコードに記述し、外部入力をマッチング対象の文字列としてだけ使う処理は、パターンのコンパイルに外部入力が関与しません。

# パターンは開発者が定義した固定の正規表現
# 外部入力(params[:code])はマッチング対象の文字列として使う
PRODUCT_CODE = /\A[A-Z]{3}-\d{4}\z/
PRODUCT_CODE.match?(params[:code])

一方、次のように外部入力がパターンそのものになる処理は、入力元と到達経路の確認が必要です。

# 利用者が指定した文字列を正規表現としてコンパイルする
pattern = Regexp.new(params[:pattern])
pattern.match?(text)

# 正規表現リテラルへ外部入力を展開する
text.match?(/#{params[:keyword]}/)

いずれのコード例も、記事の説明用に作成したもので、実行環境での動作は確認していません。外部入力の例として params を示していますが、Web リクエストに限らず、データベースに保存された利用者の設定値、アップロードされたファイル、外部 API の応答、設定ファイルなど、攻撃者が内容を制御できる可能性がある入力元はすべて確認対象です。

Regexp.timeout と入力文字数制限で防げない理由

Ruby 公式は、Regexp.timeout ではこれらの不具合を防げないと明言しています。また、一部の不具合は短いパターンでも発生するため、パターンの長さを制限しても確実な対策にはならないとしています。両者の違いは、問題が発生する段階にあります。

ReDoS(正規表現によるサービス拒否)

マッチング処理で過剰な計算時間が発生する問題です。Regexp.timeout はマッチングの制限時間を設定する仕組みで、Ruby のドキュメントでも信頼できない入力によるサービス拒否への対策として説明されています。

今回の不具合

マッチングの前の、正規表現をコンパイルする段階でメモリ破損が生じ得る問題です。計算時間の長さとは関係がないため、マッチングの制限時間では防げません。

ReDoS 対策として Regexp.timeout を設定することは引き続き有効ですが、今回の問題の緩和策としては扱わないでください。

Regexp.escape と Regexp.union の扱い

Ruby のドキュメントでは、Regexp.escape は正規表現で特別な意味を持つ文字をエスケープした文字列を返すメソッドとして説明されています。また、Regexp.union に文字列を渡すと、各文字列はエスケープされ、文字どおりに一致するパターンになります。

これらは、利用者に正規表現の構文を使わせる必要がなく、入力を固定の文字列として検索したい用途に適しています。ただし、エスケープした結果も正規表現としてコンパイルされます。Ruby 公式は Regexp.union を不具合へ到達する経路の例に挙げており、エスケープによって今回の不具合を回避できるとは説明していません。Regexp.union に正規表現オブジェクトを渡した場合はそのまま使われるため、その正規表現がどこで作られたかの確認も必要です。

固定の文字列を探すだけであれば、正規表現を使わない方法も選択できます。Ruby のドキュメントでは、String#include? は部分文字列を含むかを判定し、String#gsub などの置換メソッドは文字列のパターンを正規表現の特殊文字として扱わず、通常の文字として扱うと説明されています。エスケープは用途を限定する設計上の選択肢であり、修正版への更新を不要にする回避策ではありません。

参考: class Regexp(Ruby ドキュメント)、class String(Ruby ドキュメント)

GitLab 以外の Ruby アプリケーションへの影響

GitLab では RCE につながる可能性が確認されていますが、他の Ruby アプリケーションで同じ結果になるとは断定できません。影響は次の 3 段階に分けて考える必要があります。

確認の段階内容情報の位置付け
Ruby の不具合に到達する条件攻撃者が制御できる文字列を正規表現としてコンパイルすることRuby 公式の説明
アプリケーションで外部入力が到達する経路認証の有無、入力を指定できる利用者の範囲、入力がコンパイル処理まで加工されずに届くか各アプリケーションの実装で確認する事項
実際の悪用成立に必要な条件メモリ破損がクラッシュにとどまるか、コード実行まで成立するかGitLab では RCE の可能性が確認済み。他のアプリケーションについては公開情報からは断定できない

編集上の推論として、メモリ破損が発生した場合、少なくとも Ruby プロセスの異常終了によるサービス停止は考えられます。コード実行まで成立するかは、実行環境やメモリの状態などに左右されると考えられ、公開情報からは判断できません。そのため、RCE が成立しないと判断して対応を見送るのではなく、到達条件に該当するかどうかで更新の優先度を決めることをおすすめします。

Ruby on Rails についても、フレームワークを使用しているだけで影響するとは言えません。アプリケーションのコード、および利用している gem の中に、外部入力を正規表現としてコンパイルする処理があるかを確認してください。

Ruby の影響確認と更新手順

確認は「どの Ruby が実際に動いているか」と「外部入力を正規表現としてコンパイルしているか」の 2 点で進めます。ここで紹介するコマンドは公式ドキュメントに基づくもので、実機での実行結果は確認していません。

稼働している Ruby のバージョン確認

基本の確認方法は ruby -v です。Ruby の定数 RUBY_DESCRIPTION は ruby -v が表示するものと同じ形式のバージョン文字列で、RUBY_VERSION は実行中の Ruby のバージョンを示します。

ruby -v

ただし、シェルで確認した Ruby と、実際にアプリケーションを実行している Ruby が同じとは限りません。実行環境ごとの主な違いは次のとおりです。

実行環境確認方法注意点
OS にインストールされた Rubyアプリケーションの実行ユーザーで ruby -v を実行ディストリビューションが独自に修正を取り込む場合、表示されるバージョンだけでは判断できないことがあるため、各ディストリビューションのセキュリティ情報で修正状況を確認する
rbenv で管理された Rubyアプリケーションのディレクトリで rbenv version を実行し、有効なバージョンと設定元を確認環境変数 RBENV_VERSION、カレントディレクトリと親ディレクトリの .ruby-version、グローバル設定の順に決まる。ホームディレクトリで確認した結果はアプリケーションと異なる場合がある
RVM など、その他のバージョン管理ツールアプリケーションのディレクトリと実行ユーザーで ruby -v を実行ツールの設定によって選択される Ruby が変わるため、ツールのドキュメントで選択方法を確認する
Docker のコンテナdocker exec <コンテナ名> ruby -v で稼働中のコンテナ内の Ruby を確認ホスト OS の Ruby とは無関係。修正版にするにはベースイメージを更新してイメージを再ビルドし、コンテナを作り直す必要がある
Kubernetes の Podkubectl exec <Pod 名> -- ruby -v で確認。複数コンテナの Pod は -c でコンテナを指定同じ Deployment でも、ロールアウトの途中では Pod ごとにイメージが異なる場合がある
製品やアプリケーションに同梱された Ruby製品ベンダーの公式情報で、同梱 Ruby のバージョンと修正状況を確認OS の Ruby を更新しても、同梱された Ruby は変わらない。製品自体の更新が必要

Rails ガイドの例では、bin/rails server で Puma を起動すると、起動ログに Ruby のバージョンが表示されています。起動ログやアプリケーションのログに RUBY_DESCRIPTION を出力しておくと、稼働中のプロセスがどの Ruby で動いているかを後から確認しやすくなります。

参考: docker container exec(Docker Docs)、kubectl exec(Kubernetes Documentation)、rbenv(GitHub)、The Rails Command Line(Rails ガイド)

正規表現を生成する処理の確認

アプリケーションのソースコードから、文字列を正規表現としてコンパイルする箇所を洗い出します。まず、Regexp.new、Regexp.compile、Regexp.union の呼び出しを検索します。

grep -rnE 'Regexp\.(new|compile|union)' --include='*.rb' .

次に、正規表現リテラル内の文字列展開(#{...})を含みそうな行を検索します。このパターンは文字列中の展開やパスの組み立てなども拾うため、検出結果を目視で絞り込む前提の簡易的な検索です。

grep -rnE '(/|%r\{)[^/]*#\{' --include='*.rb' .

これらの検索で発見できるのは、正規表現を動的に生成している候補箇所です。Regexp.new が存在することと、攻撃者が制御できる入力が渡されていることは別の問題で、検索結果だけでは影響の有無を判断できません。候補ごとに、引数の文字列がどこから来て、どの処理を経由してコンパイルに届くかを追跡してください。

一方で、次のような箇所は上記の検索だけでは発見できない、または見落としやすいため、別途確認が必要です。

  • 変数に代入した正規表現リテラルを別の箇所で使う処理や、メソッドを動的に呼び出す処理
  • .rb 以外のファイル(ERB テンプレート、Rake タスク、設定ファイルから読み込むパターンなど)
  • アプリケーションが利用している gem の内部で、引数の文字列を正規表現としてコンパイルする処理
  • 検索フィルター、通知ルール、入力値の検証ルールなど、利用者や管理者がパターンを登録できる機能

コード検索と並行して、仕様書や管理画面から「正規表現を指定できる機能」を洗い出すと、確認の優先順位を付けやすくなります。参考: GNU Grep Manual

更新が難しい場合の暫定対応

Ruby 公式は、更新できない場合は信頼できない入力から正規表現をコンパイルしないよう推奨しています。すぐに更新できない場合は、次の順で検討してください。

  1. 外部から正規表現を指定できる機能と、その機能を使える利用者の範囲(認証の有無、権限)を確認する
  2. 該当機能を一時的に停止する、指定できる利用者を限定する、または正規表現ではなく固定文字列での検索に入力仕様を変更する
  3. 修正版への更新計画を立てる。Ruby 3.2 以前の系列は修正版がないため、保守対象の系列への移行を含めて計画する
  4. 更新後はプロセスを再起動し、稼働中のプロセスで修正版が動作していることを確認する

前述のとおり、入力文字数の制限や Regexp.timeout の設定は、今回の問題に対する十分な緩和策になりません。

更新後の確認チェックリスト

更新コマンドやパッケージのインストールが成功しても、稼働中のプロセスが古い Ruby のまま動き続けている可能性があります。次の順で、実際に修正版が動作していることを確認してください。

手順
修正版を導入し、イメージを再ビルドする

Ruby 4.0.9 / 3.4.12 / 3.3.13 以降を導入します。.ruby-version や Dockerfile のベースイメージなど、バージョンを指定している箇所もあわせて更新します。コンテナで運用している場合は、イメージを再ビルドしてレジストリへ登録します。

手順
プロセスの再起動と再デプロイを行う

アプリケーションサーバー、バックグラウンドジョブのワーカー、定期実行のスクリプトなど、Ruby で動くすべてのプロセスを再起動します。Kubernetes では新しいイメージで再デプロイし、ロールアウトの完了を確認します。

手順
稼働中のプロセスでバージョンを確認する

シェルの ruby -v だけでなく、稼働中のコンテナや Pod 内の Ruby、起動ログやアプリケーションログに出力した RUBY_DESCRIPTION で、修正版が動作していることを確認します。

手順
正規表現を使う既存機能の動作を確認する

検索、入力値の検証、フィルタールールなど、正規表現を利用する機能が更新前と同様に動作するかを確認します。テストスイートがある場合は、更新後の Ruby で実行します。

手順
すべての実行環境で更新漏れを確認する

本番環境だけでなく、ステージング環境、バッチサーバー、CI のビルド環境、社内ツールなど、Ruby が動作する環境を棚卸しします。特に、外部入力から正規表現をコンパイルする処理を持つ環境から優先して確認してください。

GitLab の Ruby 修正との違い

GitLab は、自身が配布する Ruby に独自のパッチを適用することで、これらの問題に対応しています。GitLab 19.5.1 などのリリースノートでも、Linux package(Omnibus)とクラウドネイティブイメージ(CNG)の Ruby に正規表現のパッチを追加する変更が記載されています。

そのため、サーバーの OS にインストールされた Ruby を 4.0.9 などへ更新しても、GitLab 自体の対策にはなりません。反対に、GitLab を更新しても、同じサーバーや別のサーバーで動いている独立した Ruby アプリケーションの Ruby は修正されません。両者は別の対応として管理してください。

GitLab の管理者は、Ruby の修正版ではなく、GitLab の系列ごとの修正版への更新で対応します。GitLab の影響範囲、修正版の選び方、Helm chart のバージョン換算、侵害兆候の確認方法は「CVE-2026-110264 GitLab|修正版の選び方と侵害確認」で解説しています。

まとめ

今回の Ruby の修正は、外部入力を正規表現としてコンパイルする処理で発生し得るメモリ破損を対象としています。Ruby を使っているだけで影響するわけではありませんが、該当する処理を持つアプリケーションは、修正版への更新と稼働中のプロセスでの確認まで行う必要があります。

  • 4 件の CVE は GitLab が割り当てたもので、Ruby 側の不具合は 3 種類です。
  • すべての修正を含むのは 4.0.9 / 3.4.12 / 3.3.13 以降です。
  • 4.0.8 へ更新済みの環境も、4.0.9 への再更新が必要です。
  • 固定の正規表現だけを使うアプリケーションは影響を受けません。
  • Regexp.timeout や文字数制限は今回の緩和策になりません。
  • シェルではなく、稼働中のプロセスで Ruby のバージョンを確認します。
  • GitLab の対策は、システム Ruby ではなく GitLab 自体の更新で行います。

以上、最後までお読みいただきありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

関西を拠点に活動する、現役インフラエンジニア。経験20年超。

大手通信キャリアにて、中〜大規模インフラ(ネットワーク・サーバ・クラウド・セキュリティ)の設計・構築およびプロジェクトマネジメントに従事。現場で直面した技術課題への対処や、最新の脆弱性情報への実務対応を、一次情報として発信しています。

保有資格
CCIE Lifetime Emeritus(取得から20年以上)/ VCAP-DCA / Azure Solutions Architect Expert

▶ 運営者プロフィール(詳細)

目次