GETコレクションエンドポイントにおけるセキュリティチェックの欠落により、基本的なCoopCycleアカウントを持つユーザーであれば誰でも、共有インスタンス内の全店舗のアドレス帳を取得できてしまう状態になっていました。これにより、数え切れないほどの顧客の名前、住所、郵便番号が露出しました。この欠陥は2日以内に修正され、ユーザーには最新バージョンへのアップグレードが強く推奨されています。

漏洩の仕組み

CoopCycleは、フードデリバリー協同組合で使用されているオープンソースの物流プラットフォームであり、PHPフレームワークのAPI Platformを使用してAPIを定義しています。このフレームワークでは、各操作(POST、GETなど)にセキュリティ式を組み合わせる必要があります。式が省略されると、フレームワークは認可チェックを行わずにコードを実行します。

開発者は、店舗のアドレスリストを作成または更新するPOSTリクエストに対して、標準的な式である is_granted('edit', object) を使用して保護していました。これは、リクエストが単一の店舗エンティティを対象としており、フレームワークが評価するための具体的な「object」が存在するため、正しく機能します。

一方、同じリソースを読み取るGETリクエストは、コレクション /api/stores/{id}/addresses を対象としています。コレクションには単一のオブジェクトが存在しないため、同じ is_granted('edit', object) 式を適用することができません。開発者がセキュリティ行を書き漏らしたため、フレームワークはテナンシーに関係なく、認証されたすべてのユーザーに対してアドレスデータを提供してしまいました。

共有CoopCycleインスタンスでは、悪意のあるユーザーが店舗IDを順番に指定してエンドポイントにGETリクエストを送り、システムに保存されているすべての顧客の自宅住所を簡単にスクレイピングすることができました。これには、通常の権限を超えた特別な権限は必要ありませんでした。

なぜバグが見逃されたのか

この問題は単なる見落としではありませんでした。API Platformの宣言型セキュリティモデルには、「ユーザーはコレクション内の各オブジェクトと同じテナントに属していなければならない」という条件を表現する直接的な方法が欠けていました。欠落していたコードの行は、まさにフレームワークが認可を困難にしている場所に存在していたのです。

さらに問題を悪化させたのは、プロジェクトのテストスイートが、全アドレスを含むGETレスポンスを「期待される動作」として実際にアサート(検証)していたことです。言い換えれば、テストに使用されたフィクスチャがテナントをまたいだアクセスを許可していたため、自動テストがパスしてしまい、脆弱性が実質的に隠蔽されてしまったのです。この場合、テストスイートが「合格(グリーン)」を示していたことが、誤った安心感を与えてしまいました。

誰が得をし、誰が損をしたのか

  • 顧客: 氏名や自宅住所などの個人を特定できる情報(PII)が、プラットフォーム上の誰にでも露出しました。データは公開されたわけではありませんでしたが、この侵害により複数の協同組合にわたってプライバシーが損なわれました。
  • CoopCycleを利用している協同組合: テナントデータを保護するプラットフォームの能力に対する信頼が揺らぎました。まだアップグレードしていない協同組合は、露出が続くリスクに直面していました。
  • CoopCycleのメンテナー: 2日以内のパッチ適用と回帰テストの追加という迅速な対応により、悪用の窓口を限定し、責任あるオープンソースの管理責任を果たしました。しかし、この出来事は、特にフレームワーク主導のデフォルト設定に関する、より厳格なセキュリティレビュープロセスの必要性を浮き彫りにしました。

開発者や監査人が注目すべき点

  • 操作の非対称性: あるパスに対するPOST(またはその他の状態を変更する操作)が保護されている一方で、対応するGETが開放されている場合、その不一致は警告サインです。POSTが存在することは、開発者がそのリソースを保護しようとする意図を持っていることを示しています。
  • コレクションエンドポイント: 単一のアイテムではなくリストを返すものは、通常のセキュリティパターンから外れることがよくあります。一括読み取りに対して、認可チェックが明示的に追加されていることを確認してください。
  • テストスイートの現実味: フィクスチャが実際のテナンシー境界を反映していることを確認してください。テナントをまたいだデータの漏洩を検証してパスしてしまうテストは、合格の合図ではなく、警告のサインです。

修正と次のステップ

脆弱性が報告された後、CoopCycleのコアチームはGETコレクション操作に欠落していたセキュリティ式を追加し、単一アイテムとコレクションの両方のエンドポイントに対してテナントの分離を強制する回帰テストを導入しました。パッチはソフトウェアのその後のバージョンでリリースされました。

CoopCycleのユーザーは、以下の対応を行う必要があります:

  1. ソフトウェアの最新バージョンを実行していることを確認する。
  2. 同様のコレクションレベルの欠陥を導入する可能性のある、カスタム拡張機能やプラグインを確認する。
  3. すべてのAPIルートにおける読み取り/書き込みの非対称性に焦点を当てて、セキュリティスキャンを再実行する。

教訓

セキュリティを宣言的に扱うフレームワークは、開発者が単一のオブジェクトにのみ適用可能なパターンに依存してしまうと、危険な隙(ギャップ)を隠してしまう可能性があります。「エンドポイントの読み取り側は、書き込み側と同じガードを備えているか?」という単純なチェックを行うだけで、テストスイートがすべてパスしているために見過ごされてしまうような、一種のクロス・テナント・リークを明らかにすることができるのです。