9月7日、Taylor Elkinsが「A teardown of Claude for Desktop」と題した記事を公開した。855 MBのバンドルを開いてみると、Linux仮想マシン、6つのプログラミング言語、MITMプロキシという予想外の構造が現れた——Claude for Desktopは、シンプルなチャットUIの裏側に本格的なサンドボックス基盤を抱えたアプリだ。解析対象はバージョン 1.40609.1。
アプリの基本構造
外観はElectronアプリとして標準的な構成だ。バンドルの約60%はElectronフレームワークとChromiumリソースが占める。ネイティブな機能は .node バイナリファイル(AppleフレームワークとダイナミックリンクされたNode.jsネイティブアドオン)に収められており、ion-dist/(バンドルされたWebフロントエンド)と smol-bin イメージが残りの主要コンポーネントだ。
使われている言語は6種類にわたる:
- C/C++ — ElectronとChromium
- Objective-C — Squirrelアップデーター
- JavaScript — WebUIとアプリ連携
- Rust — ウィンドウ・キー・ファイルのクロスプラットフォーム処理
- Swift — SecurityやVirtualizationなどのApple API
- Go — Linuxゲスト内のデーモン
サンドボックス:Linuxゲスト VMの実装が面白い
記事の中で最も興味深い部分が、サンドボックスの設計だ。
SwiftアドオンはAppleの**Virtualization.framework**にリンクしており、VM管理の型を公開している。Claude for Desktopはエージェントコードを実行する際、macOS上でLinuxゲストVMを起動し、そこで処理を行う。AnthropicがCoworkのアーキテクチャについて説明した公式ブログで言及した設計と一致する内容だ。※このURLは編集部が付加価値リンクとして追加したものであり、元記事に明示されたリンクではない。
VM導入の主な目的は2点:
- 破壊的な操作の抑止(例:
rm -rf /のような誤操作) - データ流出の防止(プロンプトインジェクションによるAPIキー等の窃取)
ゲストOSの中身
ゲストOSはランタイムにダウンロードされる(圧縮で 1.23 GB、展開後 10 GiB)。Ubuntu 22.04.5 LTS(Jammy Jellyfish)ベースで、カーネルは 6.8.0-136-generic。Node.js・Python・UV、そしてGoで実装されたデーモン sdk-daemon が含まれる。元記事に記載されたバージョン番号は記事公開時点(2025年9月7日)のものであり、転記時の誤読を避けるため原文を直接参照されたい。
ドキュメント処理スタックも充実しており、pdfplumber、pytesseract(OCR)、unoserver(ヘッドレスLibreOffice)、camelot(PDF表抽出)、markitdownなど多数のツールがプリインストール済みだ。
アプリバンドル内の smol-bin(24 MB)の役割
アプリには smol-bin という小さなイメージ(arm64とx64で各 24 MB)が同梱されている。これはブータブルOSではなく、VM起動時にマウントされる「追加ディスク」のようなものだ。
重要な設計意図がある。ゲストイメージはバージョン管理されたURLからキャッシュできるが、ホスト・ゲスト間のRPCプロトコルが変わった際にデーモン側だけ更新が必要になる。smol-bin に最新のデーモンバイナリを同梱しておくことで、ゲストイメージ全体を再ダウンロードせずにデーモンだけ更新できる仕組みだ。実際、ゲストイメージに含まれるデーモンと smol-bin のデーモンはハッシュが異なっていた。
ネットワーク制限とMITMプロキシ
srt-settings.json(Sandbox RunTime設定)には、ゲストVMのネットワークポリシーが記述されている。許可ドメインは以下の通りだ:
{
"network": {
"allowedDomains": [
"registry.npmjs.org",
"pypi.org",
"github.com",
"api.anthropic.com",
"*.anthropic.com",
"crates.io"
...
],
"mitmProxy": {
"socketPath": "/var/run/mitm-proxy.sock",
"domains": [
"*.anthropic.com",
"*.claude.com",
"*.frame.claudeusercontent.com"
]
}
}
}
Anthropicの公式ブログが言及した「悪意あるファイルがClaudeをだまし、攻撃者のAnthropicアカウント経由でワークスペースファイルをアップロードさせた」脆弱性への対策として、VM内にMITMプロキシを設置し、Anthropic APIへのリクエストにVM固有のセッショントークンを要求する仕組みが追加されている。これにより攻撃者のAPIキーを用いたリクエストは弾かれる設計だ。ただし、この仕組みはあくまでVM内部からの通信を対象としたものであり、VM外の経路やプロキシ設定の不備を突く攻撃への完全な防御を保証するものではない点には留意が必要だ。
ホスト↔ゲスト通信は vsock 経由
通信の流れはおおむね以下の通りだ:
- ElectronアプリがSwiftネイティブ層にゲストOS起動を要求
coworkdサービスがGoバイナリsdk-daemonをバックグラウンド起動- ElectronがSwiftの
CoworkVMRPCClient経由で vsock を使いゲストとJSON RPCで通信
vsock(Virtual Socket)はホスト・ゲスト間の高速なソケット通信を可能にするLinuxカーネルの機能だ。ネットワークトラフィックもvsock経由で仮想Ethernetインターフェースからホスト側に転送されており、ホスト側には VZGvisorNetworking への参照があることから、gvisor-tap-vsockベースのネットワークスタックが使われていると推測される。
ローカルMCPサーバーはVMの外で動く
記事では実際にPython製のMCPサーバーをClaudeの設定に追加し、実験を行っている。MCPツールが返したOSは Darwin(macOS)、PIDは 18717。プロセスツリーは以下の通りだった:
Claude (18616)
└── Contents/Helpers/disclaimer (18716)
└── Python MCP probe (18717)
ローカルMCPサーバーはLinux VMの外、macOSホスト上で動作する。 VMに共有されていないファイルも、macOSのパーミッションが許せばMCPサーバーから読める。VMのサンドボックス保護はVM内部で実行されるツールにのみ適用される点に注意が必要だ。
言語間ブリッジの構造
JavaScriptからSwift/Rustを呼ぶブリッジには Node-API が使われており、RustアドオンはNAPI-RSを採用している。Electron内プロセス間の通信には Electron IPC を使い、チャンネル名は以下の規則で生成される:
$eipc_message$_<build-id>_$_<namespace>_$_<BridgeClass>_$_<method>
Swift↔Goのゲストデーモン間はvsock越しのJSON RPCだ。プロトコルが変われば両サイドの更新が必要になるため、前述の smol-bin による同梱戦略が効いてくる。
詳細はA teardown of Claude for Desktopを参照していただきたい。