Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】How to Prevent Cache Poisoning in Nx and Lerna Monorepos

2026年10月14日に「Dev.to」が公開したITニュース「How to Prevent Cache Poisoning in Nx and Lerna Monorepos」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

モノレポのビルドを速めるリモートキャッシュには、「キャッシュポイズニング」というセキュリティ上の脅威がある。これは、悪意あるコードが共有キャッシュに不正な成果物を仕込み、他の開発者がそれを使ってしまう問題だ。信頼できないコードには読み取り専用トークンを与え、キャッシュへの書き込みを制限することが重要である。

ITニュース解説

モノレポ(複数のプロジェクトを一つのリポジトリで管理する開発方式)では、アプリケーションのビルドやテストに時間がかかりがちである。これを効率化し、開発を高速化するための非常に効果的な手段の一つが「リモートキャッシュ」の利用だ。NxやLernaといったツールは、一度実行されたタスクの結果やビルドによって生成された成果物をキャッシュとして保存し、その後、同じタスクで入力に変更がない限り、処理を再実行せずに保存済みのキャッシュを再利用する。これにより、開発者はもちろん、継続的インテグレーション・デリバリー(CI/CD)環境も、不要な処理をスキップしてビルド時間を大幅に短縮できる。しかし、この便利なリモートキャッシュシステムに、共通の「読み書きトークン」(認証のためのアクセスキーのようなもの)を単一で利用すると、実は見過ごされがちな、しかし重大なセキュリティリスクが生じる。これが「キャッシュポイズニング」と呼ばれる問題である。

キャッシュポイズニングとは、悪意のある攻撃者がリモートキャッシュに不正なデータ(改ざんされたビルド成果物など)を仕込み、他の開発者やCI/CDシステムがその不正なデータを信頼して利用してしまうことで発生するセキュリティ上の脅威だ。記事ではこのリスクをCVE-2025-36852 (CREEP) という脆弱性として説明している。この問題の核心は、ビルドを実行できる人であれば誰でも、共有されているキャッシュにデータを書き込めてしまう点にある。典型的なチーム開発やオープンソースプロジェクトのワークフローでは、プルリクエスト(コードの変更提案)が送られると、自動的にテストやビルドが実行されることが多い。もしリモートキャッシュが読み書き両方に一つのトークンしか使っていない場合、次のような攻撃シナリオが考えられる。攻撃者は、プルリクエストを通じて、何らかの悪意のあるビルドロジックや依存関係をプロジェクトに導入する。すると、CIパイプラインはそのプルリクエストのコードを使ってビルドを実行し、結果として生成された成果物をリモートキャッシュにアップロードする。Nxのタスクハッシュ(タスクの入力から計算される一意の識別子)は、入力内容が変わらなければ同じ値になるため、攻撃者はメインブランチが将来同じ入力で計算するであろうハッシュ値を予測し、そのハッシュ値の下に、自身が不正に改ざんした成果物をアップロードするのだ。Cacheiroのようなコンテンツアドレス型キャッシュ(データの内容に基づいてハッシュ値を生成し、そのハッシュ値でデータを管理する方式)は、既存のハッシュ値に対して上書きを試みると「409 Conflict」エラーを返し、最初の書き込みを優先する。このため、一度攻撃者が不正な成果物を仕込むと、そのデータはキャッシュに残り続けてしまう。そして、後日メインブランチでのビルドや他の開発者が同じタスクを実行した際、リモートキャッシュからダウンロードされるのは、攻撃者によって「ポイズニングされた(毒された)」不正な成果物であり、それを信頼して利用してしまうことになる。Nxが2026年5月に公式の自己ホスト型キャッシュパッケージを非推奨としたのは、まさにこのCREEPというキャッシュポイズニングのリスクが背景にあったのだ。この問題への根本的な解決策は、信頼できないコードがキャッシュからデータを「読み込む」ことはできても、キャッシュにデータを「書き込む」ことはできないように、読み込みと書き込みの権限を明確に分離することだ。

キャッシュポイズニングを防ぐための具体的な解決策は、キャッシュへのアクセス権限を「読み込み」と「書き込み」で分けることである。つまり、「リードオンリートークン」(読み込み専用のアクセスキー)を導入する。Cacheiroという自己ホスト型のリモートキャッシュサーバーでは、バージョン1.3.0以降でこの専用のリードオンリートークンがサポートされている。このトークンを使った場合、キャッシュからのデータダウンロード(GETリクエスト)は許可されるが、新しいタスクの成果物をキャッシュにアップロード(PUTリクエスト)しようとすると、「403 Forbidden」というエラーで拒否される。また、有効なトークンが提供されていないか、未知のトークンが使われた場合は「401 Unauthorized」エラーが返される。リードオンリートークンの利用にはいくつかルールがあり、これらはサーバーの起動時に厳密にチェックされる。まず、通常の書き込み権限を持つトークン(auth.token)が設定されていることが必須である。次に、リードオンリートークンは書き込みトークンとは異なる値でなければならず、空の値であってはならない。これらのルールが守られていない場合、サーバーは起動を拒否する。これにより、意図しない設定ミスによるセキュリティ上の抜け穴を防ぎながら、安全にキャッシュへのアクセスを制御できる。

Cacheiroでリードオンリートークンを実際に利用するには、サーバー側とクライアント側の両方で設定が必要になる。サーバー側の設定として、Dockerイメージを使用している場合、docker runコマンドを実行する際に環境変数として二つのトークンを指定する。具体的には、CACHEIRO_AUTH_TOKENには読み書き両方が可能な「スーパーシークレット書き込みトークン」を、そしてCACHEIRO_AUTH_READ_ONLY_TOKENには「読み込み専用トークン」を設定する。Cacheiroをnpmライブラリとしてアプリケーションに組み込む場合は、設定オブジェクト内のauthプロパティに、tokenとreadOnlyTokenというキーでそれぞれのトークン文字列を割り当てる。クライアント側の設定では、NxやLernaがリモートキャッシュにアクセスする際に使用するトークンを、NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKENという環境変数で指定する。ここで重要なのは、このトークンを「信頼されたパイプライン」と「信頼できないパイプライン」で使い分けることだ。例えば、メインブランチへのマージやリリース用のビルドなど、信頼できるワークフローでは、キャッシュへの読み書き両方が可能な「書き込みトークン」を割り当てる。これにより、正規のビルド成果物がキャッシュに保存される。一方、プルリクエストの検証など、まだコードが完全に信頼できない可能性のあるワークフローでは、「リードオンリートークン」を割り当てる。これにより、そのプルリクエストのビルドは既存のキャッシュを利用して高速化できるが、不正な成果物を共有キャッシュにアップロードすることはできなくなる。書き込みトークンは非常に機密性が高いため、その管理は厳重に行う必要がある。プルリクエストワークフローからアクセスできないシークレットとして安全に保管し、フォークされたリポジトリのコードが実行されるようなワークフローには、絶対に公開してはならない。また、Cacheiroサーバーがプライベートネットワーク外からアクセス可能な場合は、HTTPSを設定して通信を暗号化することで、トークンの漏洩リスクをさらに低減することが推奨される。

共有のCI/CDパイプラインでは厳格な認証がセキュリティ上不可欠である一方、個人のローカル開発環境では、毎回トークンを設定する手間が開発の妨げになる場合もある。Cacheiroでは、このような利便性を考慮し、バージョン1.4.0から認証を任意に設定できるようになった。Dockerイメージを使用する際にCACHEIRO_AUTH_TOKEN環境変数を省略すると、認証なしでCacheiroサーバーを起動できる。同様に、ライブラリとして利用する場合も、設定オブジェクトからauthプロパティ自体を省略することで、認証なしの状態となり、リクエストはトークンなしで受け入れられる。ただし、認証を無効にする際にはいくつか重要な注意点がある。auth.tokenを設定せずにauth.readOnlyTokenだけを設定することはエラーとなり、認証なしのサーバーでリードオンリートークンだけが機能するような状態にはならない。これは、セキュリティを確保するための設計である。また、Cacheiroの参照ランナー(cacheiro-runner)では、デフォルトでauth.tokenがchange-meという値に設定されているため、環境変数を省略するだけでは認証が無効にならない点も覚えておくべきだ。認証を無効にするには、authオブジェクト自体を省略するか、Docker環境変数でCACHEIRO_AUTH_TOKENを指定しないようにする必要がある。さらに、トークンとして空の文字列を渡すことで認証を無効にする方法は現在も機能するが、これは非推奨であり、将来のメジャーバージョンでは拒否されるようになるため、推奨されない。認証が必要ない場合は、フィールド自体を省略する方が良い。最も重要な注意点として、認証なしでCacheiroを実行できるのは、ローカルホスト(自分のPC内)や、他の誰もがアクセスできないような完全に隔離されたプライベートネットワーク内のみに限定すべきである。外部からアクセス可能な環境で認証を無効にすると、セキュリティリスクが非常に高まるため、決して行ってはならない。

このように、モノレポ開発におけるリモートキャッシュは、ビルドを高速化する上で非常に強力なツールであるものの、安易な運用はキャッシュポイズニングという重大なセキュリティリスクを招く可能性がある。このリスクは、信頼できないソースからのコードが不正な成果物をキャッシュに注入することで発生し、他の開発者やシステムに深刻な影響を与えることになる。この問題への対策としては、キャッシュへの読み込みと書き込みのアクセス権限を明確に分離し、リードオンリートークンを適切に利用することが強く推奨される。これにより、信頼できるビルドのみがキャッシュを更新し、それ以外のビルドは既存のキャッシュを利用するだけに留めることが可能となる。ローカル開発環境での利便性も考慮しつつ、共有環境では厳格なセキュリティ対策を講じることで、高速かつ安全な開発プロセスを確立できるのだ。

関連コンテンツ

関連IT用語

関連ITニュース