署名や送金ができるページに第三者の監視スクリプトを置かない:Polymarket と DebugBear の事例
ログイン済みの利用者が署名・発注できるページでは、性能監視(RUM)などの第三者スクリプトも利用者と同じ権限で動く。秘密鍵を盗まなくても、ページ内の署名機能を呼べば資産は動かせる。
何が起きたか
- 予測市場 Polymarket で、サイトに埋め込んでいた性能監視スクリプト(DebugBear の配信先)が改ざんされ、一部利用者のログイン済みセッションで資産の売却・送付が行われた。
- Hudson Rock の静的解析では、スクリプトは localStorage の認証情報を読み、React コンポーネントの props やフックの状態をたどって取引クライアントと署名機能を探し、利用者の権限で資産移動の署名を求める設計だった。秘密鍵を外へ送る処理は確認されていない。
- 同社はスクリプトとキャッシュの除去、取引の一時停止、全セッションのリセットを行い、影響ウォレットの 95% で全額返金を済ませたとしている。
防ぎ方
- 重要ページから第三者スクリプトを外す: 署名・送金・決済・管理画面など「利用者の権限で取り返しのつかない操作ができるページ」では、解析・監視・チャットなどの外部スクリプトを読み込まない。必要ならページを分ける。
- CSP の script-src を絞る: 読み込めるスクリプトの配信元を許可リストにし、
unsafe-inlineを避ける。Polymarket も CSP の強化を進めている。 - 版を固定し SRI を付ける: 外部スクリプトは版付き URL に固定し、
integrity属性(Subresource Integrity)でハッシュを照合する。配信元で中身が差し替わっても読み込まれない。「最新を常に配る」タグは SRI が使えないので、重要ページには置かない。 - サンドボックス化する: どうしても必要な監視は、別オリジンの iframe(
sandbox属性付き)や Web Worker に閉じ込め、メインページの状態や署名機能に触れさせない。 - 署名要求を利用者に見せる: ウォレット側で、予期しない署名要求は内容を表示して拒否できるようにする。Hudson Rock も「予期しない署名要求は拒否し、履歴を確認する」よう勧めている。
注意点
- 自前で運用する解析スクリプトでも同じことが起きる(共通で読み込む自前運用の解析スクリプトがカードスキマーの配信元になる(Convertr / Plausible CE))。
- 認証情報を localStorage に置くと、同じページの全スクリプトから読める。HttpOnly Cookie など、スクリプトから読めない保存先を検討する。