2026年5月12日、RubyGems.orgが運用以来初めて新規ユーザー登録を一時停止する事態が発生した。BufferZoneCorpを名乗る攻撃者が数百個の悪意あるGemとGoモジュールをスリーパー型で配信網に投入し、配信基盤のwebhook機能を中継器として悪用していたためだ。本記事ではRubyGems.orgのステータスページ、関連PR、メンテナのMaciej Mensfeld氏の公開情報をもとに、攻撃のタイムライン、該当パッケージ、確認手順をMermaid図と表で整理する。

サプライチェーン全体のリスク像と防御策の俯瞰はサプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリストをご覧ください。

情報ソースに関する注記(2026-05-13 時点)

  • RubyGems公式からのインシデント報告・ブログ記事・CVE/GHSA は本記事執筆時点(2026-05-13)で未公開。
  • 本記事の情報は status.rubygems.org のステータスページ、rubygems/rubygems.org の関連PR(#6485 / #6486 / #6499 / #6500)、メンテナ Maciej Mensfeld 氏の公開ツイート、および The Hacker News の報道に基づいている。
  • 攻撃ペイロードの詳細(具体的な窃取コード、C2エンドポイントのフルパス、被害件数)は一次ソースでまだ網羅的に開示されていないため、本記事は公開情報の範囲で整理している。公式声明が出た時点で内容を更新する予定。

対象読者

  • Ruby on Rails や Sinatra で gem install または bundle install を回す全開発者・全CI環境。
  • Go の go get または go install を使っているプロジェクト、特に github.com/BufferZoneCorp/* を参照する依存を持つ開発者。
  • RubyGems の API キー、~/.gem/credentials~/.netrc~/.npmrc が置かれた開発マシンを管理するセキュリティ担当者。

1. RubyGemsで何が起きたか――BufferZoneCorp攻撃の全体像

2026年5月12日 08:54 UTC、status.rubygems.org が「DDoS attack」と表現した障害を公表し、新規ユーザー登録を一時的に停止する措置を取った。表向きの説明はDDoSだが、内実は単純な外部からの大量リクエスト攻撃ではない。後述するように、配信基盤自身のwebhook機能を踏み台に外向きHTTPリクエストを発生させる「増幅型」の内部悪用だった。

攻撃者は BufferZoneCorp を名乗るGitHubアカウントを2026年4月20日に作成し、Ruby側7リポジトリ、Go側10リポジトリの計17リポジトリを公開した。スリーパー型と呼ばれる典型的なサプライチェーン攻撃の手口で、最初は無害なバージョンを公開して信頼を獲得し、後から悪意あるバージョンに更新する戦術だ。

本記事の独自視点

  • 「DDoS」と表現された障害の正体は、RubyGems.org自身のwebhook test-fireエンドポイントを使った増幅悪用だ。外部からの帯域攻撃ではない。
  • メール未確認アカウントでもAPIキーを発行・gem pushできた仕様の穴が、攻撃者のスケール戦術を支えていた。
  • 2026年5月12日時点でBufferZoneCorpのGitHubアカウントは引き続き公開状態で、Goモジュールは取得可能だ。RubyGems側の応急処置は配信側に閉じている。

攻撃の流れを俯瞰すると次のようになる。攻撃者の準備、配信網への侵入、被害者への到達、RubyGems側の応急処置の4段階に分かれる。

flowchart TD A["BufferZoneCorpがGitHubアカウント作成"] --> B["17リポジトリを準備し無害バージョン公開"] B --> C["スリーパー期間で信頼を獲得"] C --> D["RubyGemsにメール未確認APIキーでアカウント量産"] D --> E["悪意あるバージョンを大量push"] E --> F["被害者がgem install/go getで取得"] F --> G["extconf.rbまたはinit関数が自動実行"] G --> H["環境変数とSSH鍵をwebhook.siteへ送信"] E --> I["RubyGemsがDDoS表現で公表しyank対応"] I --> J["新規登録停止とwebhookレート制限を投入"]

注目すべきは、攻撃者がパッケージ配信そのものだけでなく、配信基盤の機能を二次的に悪用していた点だ。RubyGems.orgには gem ごとに任意のwebhook URLを登録できる機能があり、test-fire エンドポイントを叩くと運営側のサーバから登録URLへHTTPリクエストが飛ぶ。攻撃者はこの test-fire を踏み台にして、運営インフラから任意の外部宛にリクエストを発生させていた。これがステータスページで「DDoS」と表現された現象の実態である。

ステータスページの表現は外部広報向けの単純化で、実態は内部リソースの増幅悪用だった。SSRF(Server Side Request Forgery)に近い構造を持つこの手口は、対外的にはDDoSに見えるが、防御側の対策はレート制限と認証強化に寄ることになる。


2. DDoSの正体――webhookとAPIキーのRubyGems攻撃ベクタ

RubyGems.org の応急処置PRを時系列で並べると、攻撃者が突いた弱点が浮かび上がる。表向きの「DDoS」公表の裏で、配信基盤自体の設計上の穴が一気に塞がれた経緯がわかる。

時刻 PR 内容 役割
2026-05-11 14:53 UTC #6486 提出 メール未確認アカウントのAPI利用を遮断 攻撃者のスケール戦術を根本封鎖
2026-05-11 16:45 UTC #6486 merged 同上のマージ 新規アカウント量産が止まる
2026-05-12 04:54 UTC #6485 大量yankのバックグラウンドジョブ化 悪意あるバージョンの一括削除を高速化
2026-05-12 08:35 UTC #6499 webhook test-fire の Rack::Attack レート制限 増幅悪用の遮断
2026-05-12 08:35 UTC #6500 新規ユーザー登録の停止 アカウント量産の物理的ブロック
2026-05-12 08:54 UTC status公表 「DDoS attack」として障害を公表 外部広報

PR #6486 の中身が特に重要だ。RubyGems.org のユーザー登録は通常のWebサービス同様にメール確認を介する設計だったが、確認が未完了でもAPIキーは発行可能で、gem push まで通る状態が放置されていた。攻撃者はこの抜け穴を使い、捨てメールアドレスで大量にアカウントを作って即座に悪意あるGemを公開していた。

PR #6486 が塞いだ穴の意味

  • メール確認なしでAPIキーが発行できる状態は、認証フローの「中間状態」がそのまま本番権限を持っていたのと同じだ。
  • 量産対策としてのCAPTCHAやレート制限よりも、根本的な認証境界の見直しが先だったといえる。
  • 同種の穴は他のパッケージレジストリにも残っている可能性が高い。自社が運用するレジストリで同じ落とし穴を抱えていないか点検する材料になる。

PR #6499 が塞いだ webhook test-fire の悪用は、攻撃者が自前のサーバ帯域を使わずに大量の外向きリクエストを発生させる手口だった。test-fire は本来、開発者が webhook 設定を確認するための機能で、運営側から登録URLへHTTPリクエストを送る仕組みだ。攻撃者はこれを高頻度で叩き、外部の任意エンドポイントを叩かせていた。

Rack::Attack によるレート制限が入ったことで、test-fire 単位での増幅が抑制された。ただし、認証付きAPIに対する似た構造のエンドポイントは他にも存在するため、運営側は継続的な点検が必要になる。

webhook test-fire の悪用フローは次のような構造だ。攻撃者が直接外部標的を叩くのではなく、RubyGems.orgを経由させることでIP評価や帯域の問題を回避していた。

flowchart LR A["攻撃者ホスト"] -->|"test-fire APIを高頻度呼び出し"| B["RubyGems org サーバ"] B -->|"登録URLへHTTPリクエスト"| C["攻撃者制御の中継URL"] C -->|"任意の外部標的へ転送"| D["外部の被害ホスト"] style B fill:#fff3cd

3. Rubyとgolangの両刀攻撃――extconf.rbとinit関数のサプライチェーン悪用

BufferZoneCorpはRubyとGoの両エコシステムを同時に狙った。それぞれの言語処理系が持つ「インストール時に自動実行されるフック」を悪用しており、被害者は明示的にコードを呼び出さなくても感染する。

Ruby側の攻撃面はextconf.rbだ。これはC拡張を持つGemをインストールする際にネイティブビルド設定を行うためのスクリプトで、gem install の過程で必ず実行される。攻撃者は本来のビルド設定の前後に環境変数とSSH鍵の窃取コードを差し込み、ビルド失敗時でも窃取は完了するように仕込んでいた。

Go側の攻撃面はinit()関数だ。これはパッケージがインポートされた瞬間に自動実行される仕組みで、被害者のコードがその関数を明示的に呼ばなくても起動する。攻撃者はinit()内でCI環境を検出し、開発者マシンとCIの両方で異なるペイロードを実行する分岐ロジックを仕込んでいた。

両者の違いを比較すると、Rubyは「インストール時」、Goは「ビルド・実行時」のタイミングで起動する点で時間軸が異なる。検知のポイントもそれぞれ別になる。

言語 起動ポイント 検知が難しい理由 対策の方向性
Ruby gem install 時の extconf.rb ビルド失敗でも窃取は完了する Bundler の sandbox オプションと Gemfile.lock の事前監査
Go パッケージインポート時の init関数 コード呼び出しなしで起動 go mod graph と vet によるinit走査

ペイロードは両言語とも以下の情報を狙っていた。一般的な認証情報の総ざらえ型で、開発者マシンが標的のときの定番セットだ。

窃取対象の認証情報

  • 環境変数全般(CIシークレットを含む)。
  • SSH 秘密鍵(~/.ssh/id_rsa 等)。
  • AWS 認証情報(~/.aws/credentials)。
  • ~/.npmrc~/.netrc に保存されたトークン。
  • GitHub CLI の設定ファイル。
  • RubyGems のAPIキー(~/.gem/credentials)。

これらはwebhook.siteに作られた攻撃者制御のエンドポイントへHTTPS POSTで送信されていた。webhook.siteは本来開発者がwebhookをデバッグするための無料サービスだが、サブドメイン形式で誰でも自由にエンドポイントを作れるため、攻撃者にとっては事前の準備コストが極めて低い窃取先となる。

攻撃者が webhook.site を選んだ理由は、TLSの有効な汎用ドメイン宛のPOSTが企業ネットワークの監視やDLPで弾かれにくい点にある。これは攻撃側の運用設計として整っており、検知側は通常のHTTPS外向き通信の中から悪意あるPOSTを区別する仕組みが必要だ。


4. 該当パッケージ一覧と窃取対象――BufferZoneCorpのRubyGems・Goモジュール

確認されている悪意あるパッケージは以下のとおりだ。Ruby側はknot-*という命名パターンで、いずれも実在の人気Gemに似せた名前を付けている。タイポスクワッティング(typosquatting)と呼ばれる手口の典型だ。

エコシステム パッケージ名 名前の元ネタ
RubyGems knot-activesupport-logger activesupport
RubyGems knot-devise-jwt-helper devise-jwt
RubyGems knot-rack-session-store rack-session
RubyGems knot-rails-assets-pipeline sprockets/propshaft 周辺
RubyGems knot-rspec-formatter-json rspec-formatter 系
RubyGems knot-date-utils-rb date 拡張系
RubyGems knot-simple-formatter simple-formatter 系
Go github.com/BufferZoneCorp/go-metrics-sdk metrics SDK系
Go github.com/BufferZoneCorp/go-weather-sdk weather SDK 系
Go github.com/BufferZoneCorp/go-retryablehttp hashicorp/go-retryablehttp
Go github.com/BufferZoneCorp/go-stdlib-ext 標準ライブラリ拡張系
Go github.com/BufferZoneCorp/grpc-client grpc-go 系
Go github.com/BufferZoneCorp/net-helper ネット系ユーティリティ
Go github.com/BufferZoneCorp/config-loader 設定ローダ系
Go github.com/BufferZoneCorp/log-core ログコア系
Go github.com/BufferZoneCorp/go-envconfig sethvargo/go-envconfig

Ruby側のknot-*プレフィックスは、本物のGemにはほぼ存在しない接頭語だ。これは攻撃者が単純なタイポスクワッティング(名前の打ち間違い)ではなく、「補助ライブラリ風」の名前付けで開発者の信頼を狙った可能性が高い。実在Gemの「補助」「ヘルパー」を装ったパッケージは、READMEや使用例の解説記事と組み合わせて被害者を誘導するパターンが多い。

Go側はオリジナルとそっくりのリポジトリ名で、メンテナ名だけがBufferZoneCorpに置き換わっている。go getを打つ際に、開発者が公式組織名(hashicorpやsethvargo)と取り違えるとそのまま感染する。Goは現状でもgithub.com/BufferZoneCorp/*が引き続き取得可能であり、Ruby側の応急処置だけでは閉じない。

Go側でまだ残っているリスク

  • BufferZoneCorpのGitHubアカウントとリポジトリは2026年5月12日時点でlive。
  • go get github.com/BufferZoneCorp/... は今も成功する。
  • GitHub の Trust & Safety への通報、または社内プロキシでのドメインブロックが必要。

スリーパー型の典型として、最初の数バージョンは無害なコードを公開し、信頼が積もったタイミングで悪意あるバージョンを後出しする。日付ベースの単純判定(「最近作られたから危険」)では検出できないため、コミットの内容差分やextconf.rb/init()の存在を見る必要がある。

スリーパー型攻撃のライフサイクルを図解すると次のようになる。RubyGemsで頻繁に観測される手口で、本攻撃ではRuby側とGo側で並行して同じパターンが回されていた。

sequenceDiagram participant A as "BufferZoneCorp" participant R as "RubyGems org" participant V as "被害者" A->>R: "無害な初期バージョンpush" R-->>V: "信頼性のあるバージョンを配信" Note over A,R: "スリーパー期間 数週間" A->>R: "悪意ある後続バージョンpush" R-->>V: "更新バージョンとして配信" V->>V: "extconf rb または init が起動" V->>A: "認証情報をwebhook siteへ送信"

5. 該当パッケージを確認する手順――RubyGems・Go両環境のセルフチェック

自分の開発環境とリポジトリが影響を受けているかは、ファイル単位の単純な grep で確認できる。被害判定の判定フローを先に俯瞰したうえで、具体的なコマンドに進む。

flowchart TD A["プロジェクトのGemfile lockとgo sumを開く"] --> B{"BufferZoneCorp系の文字列が含まれるか"} B -->|"含まれる"| C["即座に該当依存を除去しトークン無効化へ"] B -->|"含まれない"| D{"開発マシンに直接gem installまたはgo getした履歴があるか"} D -->|"履歴がある"| E["インストール済みパッケージを一覧化し削除確認"] D -->|"履歴がない"| F["継続監視 RubyGems 公式アナウンスをウォッチ"] C --> G["webhook siteへの外向き通信をログから確認"] E --> G

具体的なコマンドは最小限に絞った。確認用のワンライナーだけで、追加のスクリプトは入れない。

# RubyGems側:Gemfile.lockとローカルインストール済みgemを確認
grep -E "knot-(activesupport-logger|devise-jwt-helper|rack-session-store|rails-assets-pipeline|rspec-formatter-json|date-utils-rb|simple-formatter)" Gemfile.lock
gem list | grep -E "^knot-"

# Go側:go.sumとモジュールキャッシュを確認
grep "github.com/BufferZoneCorp/" go.sum
ls $(go env GOMODCACHE)/cache/download/github.com/!buffer!zone!corp 2>/dev/null

このコマンド群は読み取り専用で、誤って何かを書き換えるリスクはない。CI上で安全に流せるため、社内の複数リポジトリに対しても一斉点検できる。結果が空でなければ即座に対応に進む。

該当が見つかったときの対応順序

  • 該当する依存を Gemfile / go.mod から削除し、ロックファイルを再生成する。
  • 開発マシンに保存されているRubyGems APIキー、GitHub PAT、AWS、SSHキーをすべて失効・ローテーションする。
  • 過去2週間の外向きHTTPS通信ログから webhook.site 宛の POST を抽出し、流出した可能性のある情報を特定する。
  • CIで該当依存をビルドしていた場合は、CIシークレットの全件ローテーションを優先する。

注意点として、開発者個人の認証情報が漏れた可能性がある以上、単に該当Gemを削除するだけでは不十分だ。extconf.rbinit() が一度走った時点で窃取は完了しているため、痕跡を残さないアウトバウンド送信が成立している。クレデンシャル失効を必ずセットで行う。


6. RubyGems側の応急処置と残っているリスク――BufferZoneCorpはまだlive

RubyGems側の対応は配信基盤に閉じた応急処置で、攻撃者本体を排除する措置までは含まれない。整理すると次の4点が直近で実施された。

RubyGems org が実施した4つの対応

  • APIキー発行時のメール確認を強制(PR #6486)――新規アカウント量産の根本封鎖。
  • 大量yank処理のバックグラウンドジョブ化(PR #6485)――悪意あるバージョンの一括削除を高速化。
  • webhook test-fire への Rack::Attack レート制限(PR #6499)――増幅悪用の遮断。
  • 新規ユーザー登録の停止(PR #6500)――攻撃継続中のアカウント量産を物理的にブロック。

これらはいずれもRubyGems側のサービス改修であり、攻撃者のGitHub上の本拠地――BufferZoneCorpアカウントと17リポジトリ――には触れていない。本記事執筆時点でGitHub側はこのアカウントを停止しておらず、Goモジュールは引き続きgo getで取得可能だ。

なお、RubyGems公式からの正式なインシデント報告、ブログ記事、CVE/GHSA採番は2026年5月13日時点でいずれも未公開である。配信側の応急処置PRとステータスページの短い告知のみが一次情報となっており、攻撃の詳細・被害規模・最終的な是正措置についての公式声明はまだ出ていない。利用者側としては、公式が情報を整理する前段階のため、PR記述とセキュリティ研究者の公開情報を頼りに先回りで対策する必要がある。

つまり防御側の責務は、RubyGems側の応急処置に依存せず、自社環境で能動的にBufferZoneCorpへのアクセスを遮断することにある。具体的にはプロキシでのドメインブロック、社内Goプロキシでの BufferZoneCorp 配下モジュールの拒否、SBOMでの組織名検査などが現実的だ。

残っているリスクは大きく3つに整理できる。RubyGems側、GitHub側、社内CI側のそれぞれで別の対策が必要だ。

リスク領域 現状 必要な対策
RubyGems側 yank済みだが、攻撃者は別ユーザー名で再侵入可能 レジストリ側で組織名・コミットパターンの異常検知
GitHub側 BufferZoneCorpアカウントとリポジトリが公開状態のまま Trust & Safety 通報、社内DNS/プロキシでのブロック
社内CI側 webhook.site への外向き通信が許可されている可能性 外向きHTTPS のドメイン許可リスト方式への移行

CIでwebhook.siteへの外向き通信がブロックされていないと、別の攻撃者が同じ手口を踏襲したときに即座に被害につながる。RubyGems経由でなくとも、npm、PyPI、Crates.io、Go modules のいずれからでも類似攻撃は仕掛けられるため、宛先制御の側で防ぐ発想が必要だ。

サプライチェーン攻撃の継続的な傾向についてはサプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリストで防御ツール群を網羅しており、今回のRubyGems攻撃と直近のTanStack公式@tanstack/*マルウェア混入|205パッケージに広がるMini Shai-Hulud npmワームを含めた直近2週間の動向をまとめている。あわせて参照してほしい。


7. 開発者が今日からできるサプライチェーン防御策

RubyGems側の応急処置が終わっても、同じ手口を別の攻撃者が再現する可能性は十分にある。開発者個人と組織の両方でできる具体的な対策を、今日からできるものに絞って整理する。

個人開発者向けの即時対策

  • gem installgo get は実行前に必ず公式組織のリポジトリURLを確認する。
  • Bundlerの--frozen/--deploymentを本番デプロイで強制し、ロックファイル外のGemが入らない状態にする。
  • ~/.gem/credentials~/.netrc~/.ssh/id_rsaの閲覧履歴を定期点検し、想定外のアクセスがないか確認する。
  • 開発マシンの外向きHTTPSログを記録しておき、webhook.site などの汎用デバッグドメインへの POST を即時アラートする。

組織として導入する場合は、レジストリ側の対策ではなく、自社のCI/CDと開発環境側で「踏みにくい」状態を作るのが先決だ。RubyGemsやGitHubの対応速度に依存しない設計が、本攻撃の最大の教訓といえる。

組織向けの中期対策

  • 社内Goプロキシ(Athens、JFrog等)を導入し、外部の任意モジュールが直接go getできる状態をやめる。
  • RubyGemsのプライベートミラーまたはアーティファクトリポジトリを経由する経路に集約する。
  • 新規Gem/モジュールの導入をPRレビューの必須項目にし、初出から一定期間(7日が目安)はインストールを保留する運用にする。
  • SBOMを自動生成し、組織名・著作権表記の異常変化を検知する仕組みを入れる。

7日のクールダウン期間が現実的な落としどころとされるのは、公開された悪意あるパッケージの大半が1週間以内に検出・削除されているためだ。この期間さえ待てば、レジストリ側または研究者コミュニティの検出網に引っかかった悪性パッケージを踏まずに済む確率が大きく上がる。

CIシークレットの扱いについても見直しの好機だ。extconf.rbinit() で窃取される環境変数の中にCIシークレットが含まれていた場合、攻撃者は被害組織の本番環境への足がかりを得ることになる。短命トークンへの移行、OIDC連携の徹底、シークレットスキャンの常時実行がいずれも有効だ。

開発者の側でできる範囲は限られているように見えるが、外向き通信制御とロックファイル監査の組み合わせだけで、サプライチェーン攻撃の被害確率は大きく下がる。RubyGems側の応急処置は今回の波を止めるための一時的な処置に過ぎず、根本対策は配信網の利用者側にあると考えるのが現実的だ。


参照ソース


関連記事: サプライチェーンセキュリティ完全ガイド2026|攻撃手法・防御ツール・実践チェックリストTanStack公式@tanstack/*マルウェア混入|205パッケージに広がるMini Shai-Hulud npmワーム