Skip to content

Instantly share code, notes, and snippets.

@diffshare
Last active December 28, 2025 00:48
Show Gist options
  • Select an option

  • Save diffshare/fee6425351a21a8cc164c3eab9883f16 to your computer and use it in GitHub Desktop.

Select an option

Save diffshare/fee6425351a21a8cc164c3eab9883f16 to your computer and use it in GitHub Desktop.
(LLM駄文なので信頼しないこと)ローカルアプリからChromeを制御する3つのアーキテクチャパターン(Native Messaging / OS固有IPC / WebSocket)を、PAD・Claude for Chrome・Claude Codeの実例を通じて解説

ローカルアプリからChromeを自動制御する技術

browser-automation-catch

はじめに

デスクトップアプリからブラウザを自動操作したい。 この要望は、RPAツールやAIエージェントの普及とともに増えている。 筆者自身も、ブラウザを自動制御する拡張機能を作りたいと考え、その技術的な仕組みを調査した。

しかし、ブラウザはセキュリティ上の理由からサンドボックス化されており、外部プロセスから直接操作することはできない。 では、Power Automate DesktopやClaude for Chromeといったツールは、どのようにしてこの制約を乗り越えているのか。

本記事では、ローカルアプリからChromeを自動制御する技術について、実際の製品のソースコード解析を交えながら解説する。 特に、2025年6月23日に公開されたClaude CodeのWebSocket Origin検証不足の脆弱性(CVE-2025-52882)を取り上げ、設計判断がセキュリティにどう影響するかを考察する。

この記事で扱うこと

  • Chrome Native Messaging API、WebSocket、Chrome DevTools Protocolの比較
  • アーキテクチャパターンの整理(Native Messagingのみ / Native Host + OS固有IPC / Native Host + WebSocket)
  • Power Automate Desktop、Claude for Chromeのソースコード解析
  • CVE-2025-52882の技術的な解説と対策
  • セキュリティとクロスプラットフォームのトレードオフ

対象読者

  • Chrome拡張機能を開発している、または開発予定の開発者
  • デスクトップアプリとブラウザの連携を検討している開発者
  • ローカル通信のセキュリティに関心のあるセキュリティエンジニア

TL;DR

  • ローカルアプリとChrome拡張の連携には Native Messaging API が基本
  • WebSocketはクロスプラットフォーム対応に便利だが、認証なしは危険
  • CVE-2025-52882:Claude Code(※IDE拡張機能。本記事で実例として取り上げるClaude for Chromeとは別製品)でWebSocketのOrigin検証不足により、悪意あるWebサイトからローカルファイル読み取りが可能だった(CVSS 8.8)
  • 教訓:「localhostは安全」は誤り。WebSocketには認証(ロックファイル + トークン等)が必須

ローカルアプリからChromeを操作する方法

ローカルアプリからChromeを操作するには、いくつかの技術的なアプローチがある。 それぞれの特徴と用途を整理する。

Chrome Native Messaging API

Chrome拡張機能とローカルアプリを接続するための公式API。

flowchart LR
    A[ローカルアプリ] <-->|何らかの通信| B[Native Host stdin/stdout]
    B <-->|Native Messaging| C[Chrome拡張]
Loading

仕組み

  • Chrome拡張機能からchrome.runtime.connectNative()またはchrome.runtime.sendNativeMessage()を呼び出す
  • Chromeが指定されたNative Host(実行ファイル)を起動
  • 標準入出力(stdin/stdout)でJSONメッセージを交換

特徴

  • Chromeが仲介するため、許可された拡張機能のみが接続可能
  • マニフェストファイルでNative Hostの実行パスと許可する拡張機能IDを指定
  • クロスプラットフォーム対応(Windows / macOS / Linux)

参考リンク

WebSocket による直接接続

Chrome拡張機能からlocalhostのWebSocketサーバーに直接接続する方式。

flowchart LR
    A[ローカルアプリ<br/>WSサーバー] <-->|ws://localhost| B[Chrome拡張]
Loading

仕組み

  • ローカルアプリがWebSocketサーバーを起動(例:ws://localhost:8080
  • Chrome拡張機能のBackground ScriptからWebSocketで接続
  • 双方向のリアルタイム通信が可能

特徴

  • Native Hostを介さずシンプルに実装可能
  • 複数クライアントからの同時接続に対応
  • 認証を実装しないとセキュリティリスク(後述するCVE-2025-52882)

注意点

WebSocketはSame-Origin Policyの対象外であり、悪意のあるWebサイトからもws://localhostに接続可能。 この方式を採用する場合は、必ず認証機構を実装する必要がある。

Chrome DevTools Protocol

Chromeのデバッグ機能を利用してブラウザを外部から制御するプロトコル。

flowchart LR
    A[ローカルアプリ] <-->|CDP| B["Chrome<br/>(--remote-debugging-port)"]
Loading

仕組み

  • Chromeを--remote-debugging-port=9222オプション付きで起動
  • 指定ポートにWebSocketで接続し、CDPコマンドを送信
  • ページ操作、DOM操作、ネットワーク監視など幅広い機能を利用可能

特徴

  • Chrome拡張機能が不要(ブラウザを直接制御)
  • Puppeteer、Playwright、Seleniumなどの自動化ツールが内部で使用
  • デバッグ用途が主であり、エンドユーザー向けアプリには不向き

用途

  • E2Eテスト自動化
  • Webスクレイピング
  • ブラウザ自動操作ツール

参考リンク

アーキテクチャパターンの整理

ローカルアプリとChrome拡張を連携させる際のアーキテクチャは、大きく3つのパターンに分類できる。

パターンA:Native Messaging のみ

最もシンプルな構成。 Native Hostがアプリ本体を兼ねるか、アプリ本体と同一プロセスで動作する。

flowchart TD
    A["アプリ本体<br/>(= Native Host)"]
    A -->|Native Messaging<br/>stdin/stdout| B[Chrome拡張機能]
Loading

特徴

  • 構成がシンプルで実装が容易
  • Native Hostの起動/終了がChromeに依存
  • 常駐型アプリには不向き(Chromeを閉じるとNative Hostも終了)

適したユースケース

  • 拡張機能からの要求に応答するだけのシンプルなツール
  • CLIツールとの連携

パターンB:Native Host + OS固有IPC(Named Pipe等)

Native Hostとアプリ本体を分離し、OS固有のIPCで通信する構成。 Power Automate Desktopが採用しているパターン。

flowchart TD
    A[アプリ本体]
    A -->|Named Pipe<br/>Unix Socket| B[Native Host]
    B -->|Native Messaging<br/>stdin/stdout| C[Chrome拡張機能]
Loading

特徴

  • アプリ本体は常駐可能(Chromeの起動状態に依存しない)
  • OS固有のIPCはブラウザからアクセス不可能(セキュア)
  • クロスプラットフォーム対応が困難

適したユースケース

  • 常駐型のデスクトップアプリ
  • エンタープライズ向けでセキュリティ要件が厳しい場合
  • 単一OS向けのアプリ

パターンC:Native Host + WebSocket

Native Hostとアプリ本体をWebSocketで接続する構成。

flowchart TD
    A[アプリ本体]
    A -->|WebSocket<br/>ws://localhost| B[Native Host]
    B -->|Native Messaging<br/>stdin/stdout| C[Chrome拡張機能]
Loading

特徴

  • クロスプラットフォーム対応が容易
  • WebSocketの柔軟性(双方向通信、複数クライアント対応)
  • 認証を実装しないとセキュリティリスク(CVE-2025-52882)

適したユースケース

  • macOS / Linux / Windows すべてに対応する必要がある場合
  • 複数のクライアントから接続される可能性がある場合
  • ただし、認証機構の実装が必須

各パターンの比較

項目 パターンA パターンB パターンC
構成の複雑さ ◎ シンプル △ やや複雑 △ やや複雑
アプリ常駐 ✗ 不可 ◎ 可能 ◎ 可能
セキュリティ ◎ Chromeが仲介 ◎ OSが保護 △ 認証必須
クロスプラットフォーム ✗ OS依存
実装の容易さ ○(認証含む)

パターン選択のフローチャート

flowchart TD
    Q1{アプリは常駐する<br/>必要がある?}
    Q1 -->|No| A[パターンA]
    Q1 -->|Yes| Q2{クロスプラットフォーム<br/>対応が必要?}
    Q2 -->|No| B["パターンB<br/>(Named Pipe / Unix Socket)"]
    Q2 -->|Yes| C["パターンC<br/>(WebSocket + 認証必須)"]
Loading

実例:Power Automate Desktop(パターンB)

Power Automate Desktop(PAD)は、MicrosoftのRPA(Robotic Process Automation)ツールであり、ブラウザ自動化機能を備えている。 Chrome拡張機能のソースコード解析から、そのアーキテクチャを推測する。

全体構成(ソースコード解析に基づく推測)

flowchart TD
    A["Power Automate Desktop<br/>(Windows アプリ)"]
    A -->|Named Pipe<br/>(推測)| B[Native Host]
    B -->|Native Messaging<br/>stdin/stdout| C["Chrome拡張機能<br/>(Background Script)"]
    C -->|chrome.scripting API| D["Webページ<br/>(Content Script)"]
Loading

Chrome拡張機能はchrome.runtime.connectNative()でNative Hostに接続し、半永続的な双方向通信を確立する。

注記: Native HostとPAD本体の間の通信方式について、公式ドキュメントには明記されていない。 MicrosoftはWindows環境でのプロセス間通信にWCF Named Pipeを多用しているため、同様の方式を採用していると推測される。 公式トラブルシューティングではcom.microsoft.pad.messagehostというNative Host名が言及されている。

主な機能として、タブ操作(取得・作成・削除・アクティブ化)、ページ操作(リロード・URL遷移)、DOM操作(クリック・テキスト入力・要素取得)、JavaScript実行(Debugger API経由)がある。

Named Pipe を採用したと推測される理由

PADがNamed Pipeを採用していると推測される理由は、以下の通り。

Windows専用アプリである

PADはWindows専用のデスクトップアプリケーションであり、クロスプラットフォーム対応の必要がない。 そのため、Windows固有のIPCであるNamed Pipeを採用できた。

エンタープライズ向けのセキュリティ要件

PADは企業向けRPAツールであり、セキュリティ要件が厳しい。 Named PipeはOSレベルのアクセス制御(ACL)が適用されるため、不正アクセスを防ぎやすい。

高速な双方向通信

Named Pipeはカーネルレベルで実装されており、WebSocketよりも低オーバーヘッドで高速な通信が可能。

セキュリティ特性

PADのアーキテクチャは、セキュリティ面で以下の特性を持つ。

ブラウザからのアクセス不可

Named Pipeはネットワークプロトコルではないため、ブラウザのJavaScriptからアクセスできない。 悪意のあるWebサイトがPADに接続することは構造的に不可能。

OSレベルの認証

Named Pipeへの接続はWindowsのセキュリティ機構で保護される。 適切なACL(Access Control List)を設定することで、許可されたプロセスのみが接続できる。

WebSocket型の脆弱性が構造的に排除される

WebSocketを使用していないため、ブラウザ経由のlocalhost接続脆弱性(CVE-2025-52882のようなパターン)は構造的に発生しない。

実例:Claude for Chrome(パターンB)

Claude for Chromeは、AnthropicのAIアシスタント「Claude」をブラウザから利用するための拡張機能。 Claude DesktopやClaude Codeと連携し、ブラウザ操作をAIエージェントが実行できる。

全体構成(macOS/Windowsでの調査 + 設計からの推測)

flowchart TD
    A[Claude Desktop / Code]
    A -->|OS固有IPC + MCP<br/>Unix Socket / Named Pipe| B["Native Host<br/>(chrome-native-host)"]
    B -->|Native Messaging<br/>stdin/stdout| C["Chrome拡張機能<br/>(Background Script)"]
    C -->|chrome.scripting API| D[Webページ]
Loading

PADと同様に、Native HostとClaude Desktop / Claude Codeの間の通信にOS固有のIPCを使用している。 少なくとも検証したOS(macOS/Windows)ではTCPポートを開かず、OS固有IPCでローカル通信している。

OS 通信方式 検証状況
macOS UNIXドメインソケット macOSで確認(パスは環境依存)
Linux UNIXドメインソケット(推測) 未検証
Windows Named Pipe Windowsで確認

パイプ名はclaude-mcp-browser-bridge-<username>形式でユーザー名を含む。

2つの Native Host

Claude for Chromeは、2つのNative Hostに対応している。

Native Host名 対応アプリ
com.anthropic.claude_browser_extension Claude Desktop
com.anthropic.claude_code_browser_extension Claude Code

拡張機能は起動時に両方への接続を試み、応答があった方と通信を確立する。 接続確認にはping/pongメッセージを使用し、10秒以内に応答がなければ次の候補を試す。

通信の2層構造(Native Messaging + OS固有IPC/MCP)

Claude for Chromeの通信は2層構造になっている。

第1層:Chrome拡張 ↔ Native Host

Chrome Native Messaging APIを使用。 これはPADと同じく、stdin/stdoutによるJSON通信。

第2層:Native Host ↔ Claude Desktop / Claude Code

OS固有IPC + MCP(Model Context Protocol)を使用。 MCPはAnthropicが策定したAIエージェント向けのプロトコルで、ツール実行やリソースアクセスを標準化している。

セキュリティ特性

PADと同様に、Claude for Chromeもセキュリティ面で優れた特性を持つ(検証したmacOS/Windowsにおいて)。

ネットワークポート不使用(確認済み環境において)

少なくともmacOS/WindowsではTCPポートを開かず、ネットワーク経由の攻撃面が削減されている。

OS固有IPCによるローカル限定通信

UNIXドメインソケットやNamed Pipeはローカルプロセス間通信専用であり、ブラウザのJavaScriptからはアクセスできない。

OSレベルのアクセス制御

セキュリティ上重要なのはパイプ名よりも、ソケットファイル/Named PipeのOS権限(所有者・パーミッション/ACL)である。 ユーザー固有のパイプ名は、主に衝突回避や誤接続防止の意味合いを持つ。

注記:アプリケーション層のセキュリティ

なお、本記事で扱った通信層のセキュリティとは別に、Claude for Chromeはアプリケーション層でのセキュリティリスク(プロンプト注入攻撃)にも対処している。 詳細は公式ブログを参照されたい。

WebSocket 方式の落とし穴

WebSocketをローカル通信に使う際には、見落としがちなセキュリティ上の落とし穴がある。 ここでは、Claude Code(IDE拡張機能)で発生したCVE-2025-52882を例に解説する。

CVE-2025-52882:何が起きたか

2025年6月23日、Claude Code(VS Code / JetBrains拡張機能)に深刻な脆弱性が公開された。

基本情報

項目 内容
CVE ID CVE-2025-52882
GHSA ID GHSA-9f65-56v6-gxw7
CVSSスコア 8.8(高)
脆弱性タイプ CWE-1385: Missing Origin Validation in WebSockets
発見者 Datadog Security Labs

影響を受けるバージョン

プラットフォーム 影響範囲 修正版
VS Code / Cursor / Windsurf 等 0.2.116 〜 1.0.23 1.0.24
JetBrains(IntelliJ / PyCharm 等) 0.1.1 〜 0.1.8 0.1.9

脆弱性の本質

Claude CodeのMCPサーバーは、localhostにWebSocketサーバーを起動していた。 問題は、このWebSocketサーバーが接続元のOriginを検証していなかったこと。 任意のWebサイトからの接続を受け入れてしまう状態だった。

攻撃シナリオ

  1. 被害者が悪意あるWebサイトを訪問
  2. サイト上のJavaScriptがポートスキャンを実行
  3. MCPサーバーのWebSocketポートを発見
  4. 認証なしで接続し、JSON-RPCコマンドを送信
  5. ローカルファイルの読み取りやコード実行が可能に

ユーザーの操作はWebサイトを開くだけ。それ以外の操作は一切不要だった。

「localhost = 安全」の誤解

この脆弱性の根本原因は、「localhostにバインドすれば外部からアクセスできない」という誤解にある。

誤解:localhostは安全

flowchart LR
    subgraph 開発者の想定
        A1[ローカルプロセス] -->|ws://localhost| B1[MCPサーバー]
        A1 -.->|✓ OK| B1
    end
    subgraph 外部からは不可能...のはず
        A2[インターネット] -.-x|✗| B2[MCPサーバー]
    end
Loading

現実:ブラウザからlocalhostに接続可能

flowchart TD
    A[悪意あるWebサイト]
    A -->|ブラウザ内のJavaScript| B["new WebSocket('ws://localhost:PORT')"]
    B -->|認証なしで接続成功!| C[MCPサーバー]
Loading

なぜこれが可能なのか

WebSocketはSame-Origin Policyの対象外である。 通常のHTTPリクエスト(fetch, XMLHttpRequest)は、異なるオリジンへのリクエストがCORSで制限される。 しかし、WebSocketはこの制限を受けない。

ブラウザはws://localhostへの接続を許可しており、悪意のあるJavaScriptがローカルサービスに接続できてしまう。

ポートスキャンも可能

ブラウザJavaScriptでのポートスキャンには制限があるものの、デフォルトポートや既知のポート範囲を試すことで発見される可能性がある。

ロックファイルによる解決

CVE-2025-52882の修正では、ロックファイル + トークン認証が採用された。 参照: https://securitylabs.datadoghq.com/articles/claude-mcp-cve-2025-52882/

修正後の認証フロー

sequenceDiagram
    participant S as MCPサーバー
    participant F as ロックファイル
    participant C as Claude Code CLI
    participant M as 悪意あるサイト

    Note over S,F: 1. サーバー起動時
    S->>S: ランダムトークン生成
    S->>F: トークンを保存<br/>(パーミッション制限)

    Note over C,S: 2. 正当なクライアント
    C->>F: トークン読み取り
    C->>S: WebSocket接続 + トークン
    S->>S: トークン検証
    S-->>C: ✓ 接続許可

    Note over M,S: 3. 悪意あるサイト
    M-xF: ファイル読み取り不可
    M->>S: WebSocket接続(トークンなし)
    S--xM: ✗ 接続拒否
Loading

なぜこれで解決するのか

ブラウザのJavaScriptには、ローカルファイルシステムへのアクセス権がない。 ロックファイルに保存されたトークンは、正当なローカルプロセスのみが読み取れる。 これにより、OSレベルのアクセス制御を認証に活用している。

他の解決策との比較

解決策 セキュリティ 実装コスト 備考
ロックファイル + トークン 採用された方式
Origin検証 ブラウザ経由には有効(※)
Named Pipe / Unix Socket WebSocket廃止が必要
ワンタイムトークン より堅牢だが実装が複雑

※ Origin検証について

ブラウザはOriginヘッダを強制的に付与し、JavaScriptから改変できない。 そのため、今回の攻撃シナリオ(ブラウザ内JavaScript)に限定すれば、Origin検証だけでも防げる。 ただし、以下のケースには無力なため、トークン認証との併用が推奨される。

  • DNS Rebinding攻撃:正規のOriginに見せかける高度な攻撃
  • 非ブラウザクライアント:curl等ではOriginヘッダを任意に設定可能

設計判断のポイント

Power Automate DesktopとClaude for Chromeの比較から見えてきた、設計判断のポイントを整理する。

セキュリティ vs クロスプラットフォーム

ローカルアプリとChrome拡張の連携において、最も重要なトレードオフは「セキュリティ」と「クロスプラットフォーム対応」である。

セキュリティを優先する場合(PADの選択)

  • Named Pipe(Windows)やUnix Socket(macOS/Linux)を採用
  • OSレベルのアクセス制御で保護
  • ブラウザからのアクセスを構造的に排除
  • その代わりOS固有の実装が必要

クロスプラットフォームを優先する場合

  • WebSocketを採用(全OSで動作)
  • 実装がシンプルで開発効率が高い
  • その代わり認証機構の実装が必須(怠るとCVE発生)

なお、Claude for Chromeは当初WebSocket方式と推測されていたが、実際にはOS固有IPC(macOS/Windowsで確認)を使用しておりパターンBに該当する。 クロスプラットフォーム対応はOS判定による分岐で実現していると考えられる。

どちらを選ぶべきか

条件 推奨
単一OS向け Named Pipe / Unix Socket
エンタープライズ向け Named Pipe / Unix Socket
個人向けクロスプラットフォーム WebSocket + 認証
開発リソースが限られている WebSocket + 認証

Native Host は本当に必要か?

Chrome拡張からWebSocketで直接接続する方式(Native Hostなし)も技術的には可能。 では、なぜPADもClaude for ChromeもNative Hostを採用しているのか。

Native Hostを使う理由

  1. Chromeの起動に依存しない常駐

    • アプリ本体はChromeが閉じても動作し続ける
    • Native Hostは必要なときだけ起動し、アプリ本体と通信
  2. OS固有IPCの使用が可能

    • Native Hostなしの場合、WebSocketで直接接続するしかない
    • Native Hostを介することで、Named Pipe/UNIXドメインソケットが選択肢になる
    • これによりブラウザからのアクセスを構造的に排除できる
  3. 権限の分離

    • Chrome拡張はサンドボックス内で動作し、ファイルシステムに直接アクセスできない
    • Native Hostを介することで、必要な権限(ファイル操作等)を安全に委譲できる

Native Hostが不要なケース

  • 拡張機能だけで完結する機能
  • アプリ側から拡張機能への一方通行の通信
  • 開発・デバッグ用途

ローカル IPC 選択のガイドライン

最後に、ローカルIPCの選択基準をまとめる。

方式 セキュリティ クロスプラットフォーム 実装コスト 推奨シーン
Named Pipe ✗ Windows エンタープライズ向け
Unix Socket △ macOS/Linux サーバー向け
WebSocket + 認証 個人向けクロスプラットフォーム
WebSocket(認証なし) 使用禁止

選択フロー

flowchart TD
    Q1{Q1. クロスプラットフォーム<br/>対応が必要?}
    Q1 -->|No| Q2{Q2. 対象OSは?}
    Q1 -->|Yes| WS["WebSocket +<br/>ロックファイル認証"]

    Q2 -->|Windows| NP[Named Pipe]
    Q2 -->|macOS/Linux| US[Unix Socket]
    Q2 -->|複数| BOTH["各OSごとに実装<br/>or WebSocket + 認証"]

    WS --> Q3{Q3. 認証は?}
    BOTH --> Q3
    Q3 -->|実装済み| OK[✓ OK]
    Q3 -->|未実装| NG["⚠ CVE発生リスク<br/>必ず実装"]

    style NG fill:#f66,stroke:#333
    style OK fill:#6f6,stroke:#333
Loading

最も重要なこと

「ローカルだから安全」という思い込みを捨てる

WebSocketをローカル通信に使う場合、認証は必須。 これはCVE-2025-52882が示した教訓であり、すべての開発者が心に留めるべきポイントである。

まとめ

ローカルアプリからChromeを自動制御する技術について、実例とともに解説した。

Power Automate DesktopはWindows専用という制約を活かし、Named Pipeによるセキュアな通信を実現していると推測される。 Claude for Chromeも同様に、OS固有IPC(macOSではUNIXドメインソケット、WindowsではNamed Pipe。Linuxは未検証だが同様と推測)を使用したパターンBを採用しており、WebSocket型の脆弱性を構造的に排除している。

一方、Claude Code(IDE拡張機能)のMCPサーバーはクロスプラットフォーム対応のためにWebSocketを採用していたが、Origin検証の欠如がCVE-2025-52882を引き起こした。

両者の比較から得られた教訓は明確である。

  • Named Pipe / Unix Socket:OSレベルの保護があり、ブラウザからアクセス不可能
  • WebSocket:クロスプラットフォーム対応が容易だが、認証なしでは脆弱性の温床

WebSocketをローカル通信に採用する場合、ロックファイル + トークン認証のような仕組みが必須である。 「localhostにバインドすれば安全」という思い込みは危険であり、Same-Origin PolicyがWebSocketに適用されない事実を常に念頭に置くべきである。

参考リンク

公式ドキュメント

CVE-2025-52882関連

Claude for Chrome関連

Power Automate Desktop関連

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment