2026年9月4日 金曜日
AI時短ラボ
検証· 約13

『分身』にコードとAPIキーを渡すツールは、自分をどう縛っているか──Munder DifflinのSECURITY.mdを読む

自分のPC上でAIエージェントの『クローン』チームを動かすharness「Munder Difflin」のSECURITY.mdは、わずか38行で脅威モデルを定義している。ネットワークリスナーなし、typed contextBridge、単一コミッター原則──ローカルファースト設計の境界線を、公式ドキュメントの一次記述から確認した。

『分身』にコードとAPIキーを渡すツールは、自分をどう縛っているか──Munder DifflinのSECURITY.mdを読む
執筆・編集:
目次

複数のAIコーディングエージェントを自宅PC上でチームとして動かすharness「Munder Difflin」(既報)は、自分のコード・APIキー・作業内容という機微な情報を、常時稼働する複数のプロセスに預ける前提のツールだ。そのリポジトリに置かれているSECURITY.mdは、たった38行という短さながら、何を守り何を守らないかの線引きを明確に書いている。今回はその全文を一次ソースとして確認した。

3行まとめ

  • Munder Difflinは「ローカルファーストのデスクトップアプリ」であり、外部への公開ネットワークリスナーを一切持たず、あるのはアプリ内のフック用サーバーが使うローカルのUnixドメインソケットだけだと明記している
  • レンダラー(画面側)はNodeへの直接アクセスを持たず、nodeIntegration: falsecontextIsolation: trueのもとで型付きのcontextBridgewindow.cth)経由でのみメインプロセスと通信する
  • すべてのfs:*/git:*のIPC呼び出しはメインプロセス側でサンドボックス化・パス検証され、エージェントの作業ディレクトリを起点に制限される。gitへのコミットは「単一のコミッター(メインプロセス)」からのみ行われ、エージェント自身が直接コミットすることはない

スコープ宣言──「ネットワークリスナーは持たない」

SECURITY.mdの「Scope」欄はこう書かれている。

Munder Difflin is a local-first desktop app. It spawns local processes in PTYs and reads/writes files under directories you register. It opens no network listeners beyond a local Unix domain socket used for the in-app hook server, and has no auth or remote surface by design.

(Munder Difflinはローカルファーストのデスクトップアプリだ。PTY内でローカルプロセスを起動し、登録されたディレクトリ配下のファイルを読み書きする。アプリ内のフック用サーバーが使うローカルのUnixドメインソケット以外、ネットワークリスナーは一切開かない。設計上、認証機構やリモートからアクセスできる面は持たない)

複数のクローンがSlackの受信箱やトリガー経由でやり取りするという、既報で紹介した機能面の華やかさに比べると、このスコープ宣言は驚くほど地味だ。だが「外部から到達可能なポートを一切開けない」という制約は、この種のツールが最初に問われる「エージェントを乗っ取られたら外から操作されないか」という懸念に対する、もっとも基本的な回答になっている。

サポート対象は「mainブランチのみ」

「Supported versions」欄には、次の一文がある。

This is an early prototype. Security fixes target the main branch only.

(これは初期のプロトタイプだ。セキュリティ修正の対象はmainブランチのみである)

古いタグへのバックポートは行われない、という宣言だ。プロダクトとしての成熟度がまだ「早期プロトタイプ」の段階にあることを、開発者自身が明記している点は率直だと感じた。

脆弱性の報告先──公開issueではなく非公開ルート

「Reporting a vulnerability」欄は、脆弱性報告を公開のissueで行わないよう明記した上で、GitHubの「Security → Report a vulnerability」タブか、開発者本人のメールアドレスへの直接連絡という2つの経路を案内している。「数日以内に受領の返信を期待できる」「修正後は〔匿名を希望しない限り〕報告者をクレジットする」という一般的な脆弱性報告プログラムの体裁を取っている。

レビュアー向けの3つの実装メモ

もっとも技術的に具体的なのが「Notes for reviewers」欄だ。3点が箇条書きで示されている。

Renderer ↔ main IPC goes through a typed contextBridge (window.cth); the renderer has no direct Node access (nodeIntegration: false, contextIsolation: true).

(レンダラー↔メイン間のIPCは型付きのcontextBridgewindow.cth)を経由する。レンダラーはNodeへの直接アクセスを持たない(nodeIntegration: falsecontextIsolation: true))

Electronアプリの典型的な脆弱性の一つは、画面を描画するレンダラープロセスがNode.jsのAPIに直接アクセスできてしまい、悪意あるWebコンテンツ(あるいは何らかの経路で注入されたスクリプト)がファイルシステムやシェルへ直接手を伸ばせてしまうことにある。nodeIntegration: falsecontextIsolation: trueの組み合わせは、Electron公式が推奨するこの種の攻撃を防ぐ基本設定であり、明示的にオフになっていることをSECURITY.mdはレビュアーに向けて宣言している。

All fs:* / git:* IPC calls are sandboxed and path-validated in the main process, rooted at an agent's working directory.

(すべてのfs:*/git:*のIPC呼び出しは、メインプロセス側でサンドボックス化・パス検証され、あるエージェントの作業ディレクトリを起点とする)

ここで示されているのは、「エージェントが指定した任意のパスをそのまま信用しない」という設計だ。ファイル操作やgit操作の要求はレンダラー側から来るが、実際の検証と実行はメインプロセス側で、エージェントごとに割り当てられた作業ディレクトリの外に出られないよう制限されている、という主張になる。

The hive commits to a local git repo from a single committer (the main process); agents only write plain files.

(このhiveがローカルgitリポジトリにコミットする際は、単一のコミッター(メインプロセス)からのみ行われる。各エージェントはただのファイルを書き込むだけだ)

複数のエージェント(クローン)が同時に動く設計であっても、実際にgitへコミットする権限を持つのはメインプロセス1つだけに絞られている、という宣言だ。エージェントそれぞれが個別にgit操作の権限を持つ設計に比べ、コミット履歴の一貫性や監査のしやすさという点で意味のある制約に見える。

実際にソースコードを開いて、2つの宣言を照合した

SECURITY.mdの3つの宣言のうち2つは、この記事のために実際にGitHubリポジトリのソースコードを開いて確認できた。1つ目、nodeIntegration: falsecontextIsolation: trueという設定は、src/main/index.tsBrowserWindow生成部分(2235行目付近)に次の通り書かれている。

webPreferences: {
  ...
  contextIsolation: true,
  nodeIntegration: false,
  ...
}

window.cthという具体的な名前も、src/preload/index.tsの末尾(1421行目)にcontextBridge.exposeInMainWorld('cth', api)という形でそのまま存在した。

2つ目、「fs:*/git:*のIPC呼び出しはパス検証される」という宣言も、src/main/fs.tssafeJoin(root, rel)という関数として実装されているのを確認した。コメントには「他のmainプロセスのモジュール(例えばgit.ts)も、呼び出し元が渡した相対パスをワークスペースのrootに対してこの同じガードで検証する。このアプリにパスエスケープのポリシーはただ1つしかなく、それはここにある」と書かれている。実装はシンプルで、渡されたパスを絶対パスに解決した上で、rootからの相対パスが..で始まるか絶対パスになっていればnullを返して拒否する、という素直なガードだった。

3つ目の「単一コミッター原則」については、src/main/git.tsを読んだ範囲では差分表示やログ取得などの読み取り系の関数が中心で、実際にコミットを書き込む処理がどのファイルに実装されているかまでは、この記事の調査範囲では特定できなかった。SECURITY.mdの宣言のうち2/3は実装コードで裏付けが取れたが、残り1つは未確認のまま、という結果になる。

SECURITY.mdの宣言 該当ファイル 確認結果
nodeIntegration: falsecontextIsolation: true src/main/index.ts 実コードに同一の設定を確認
型付きcontextBridgewindow.cth src/preload/index.ts contextBridge.exposeInMainWorld('cth', api)を1421行目に確認
fs:*/git:*のパス検証・サンドボックス化 src/main/fs.ts safeJoin()関数を確認。root外へのエスケープ(..・絶対パス)を拒否する実装
単一コミッターからのみgitへコミット 不明(git.tsは読み取り系関数が中心) 未確認。コミット処理の実装箇所を特定できず

「機微情報を機械に渡すツール」というジャンル全体への含意

複数のAIエージェントを常時稼働させて自分のコードベースを触らせる、という使い方そのものが、この1〜2年で急速に広がってきたジャンルだ。既報のMunder Difflin本編の記事でも、公式サイトが謳う「ローカルファースト」「E2E暗号化」というセキュリティ主張を紹介したが、SECURITY.mdはそのマーケティング文言の裏側にある、開発者自身がレビュアーに向けて書いた技術的な境界線だ。同種のharness・マルチエージェントツールを検討する際、README上のセールスコピーだけでなく、こうしたSECURITY.mdの有無と中身を確認する価値はありそうだと感じた。

コミット処理と過去の脆弱性履歴までは追えなかった

SECURITY.mdの宣言のうち2つはソースコードの該当箇所を実際に開いて確認できたが、「単一コミッターがgitへコミットする」という3つ目の宣言を裏付けるコード(実際にコミットを実行している関数)は、この記事の調査範囲では見つけられなかった。src/main配下にはgit.ts以外にもhive.tscontrol.tsなど数十のファイルがあり、コミット処理が別ファイルに実装されている可能性はあるが、そこまで全ファイルを読む調査はしていない。今回確認したコードも「この記事の執筆時点でmainブランチに存在した内容」のスナップショットであり、セキュリティ上のロジックが将来変わらない保証はない。過去にこのリポジトリで実際にセキュリティ上の問題が報告・修正された履歴があるかどうかについても、この記事の範囲では確認していない。Zenn検索では該当する記事は0件(2026年8月27日実測)。

関連記事: 「クローンだらけのオフィス」を自宅PCに──Munder Difflinはマルチエージェント運用をどう解決したか / 『稼働コスト表示』が実は59%過少だったバグ──累積カウンタの復元をポストモーテムで読む

感想・指摘はコメント欄へ。

シェア: ポスト はてブ

出典・参照資料

AIニュースの解説を動画でも

YouTubeでは注目ニュースの背景を解説し、Xでは新着記事をお知らせしています。

コメント

まだコメントはありません。最初のコメントを書いてみませんか?

AIについて聞きたいことはありますか?

質問箱で無料で受け付けています。回答は公開され、他の方の参考にもなります。

質問箱を見る →

新しい記事をメールで受け取る

AIの新しい発表を、出典付きで整理して届けます。

関連記事

1つのACPエージェントの中にClaude・Codex・Grokが同居する──『艦隊型』オーケストレータClaw Orchestratorの記事画像
検証09.03読了13

1つのACPエージェントの中にClaude・Codex・Grokが同居する──『艦隊型』オーケストレータClaw Orchestrator

出典 ─ Enderfga/claw-orchestr
3つのharnessを1つに『融合』させようとする個人開発、着手から10時間の記録の記事画像
検証09.03読了13

3つのharnessを1つに『融合』させようとする個人開発、着手から10時間の記録

出典 ─ galaxycoils/darius(Git
プロンプトキャッシュを壊さない会話組み立て──Gooseが「バイトを後から動かさない」設計に変えた理由の記事画像
検証09.03読了13

プロンプトキャッシュを壊さない会話組み立て──Gooseが「バイトを後から動かさない」設計に変えた理由

出典 ─ block/goose v1.46.0 リリ
Gooseの`/goal`コマンド──エージェントが「終わったつもり」で止まるのを、自己確認のループで防ぐ仕組みの記事画像
検証09.03読了12

Gooseの`/goal`コマンド──エージェントが「終わったつもり」で止まるのを、自己確認のループで防ぐ仕組み

出典 ─ block/goose v1.46.0 リリ
GooseのHooksが「拒否」を覚えた──ツール実行を止められる仕組みと、暴走したフック自体は止めない設計の記事画像
検証09.03読了13

GooseのHooksが「拒否」を覚えた──ツール実行を止められる仕組みと、暴走したフック自体は止めない設計

出典 ─ block/goose v1.46.0 リリ
Terminal-Bench開発元が作った評価基盤「Harbor」──Claude Code・OpenHands・Codex CLIを同じコマンドで数千並列評価するの記事画像
検証09.03読了13

Terminal-Bench開発元が作った評価基盤「Harbor」──Claude Code・OpenHands・Codex CLIを同じコマンドで数千並列評価する

出典 ─ laude-institute/harbor
Claude Code・Codex・Hermesを1コンテナにまとめる「HarnessRouter」──自前サーバーで動かす統一プロトコルの記事画像
検証09.03読了14

Claude Code・Codex・Hermesを1コンテナにまとめる「HarnessRouter」──自前サーバーで動かす統一プロトコル

出典 ─ harnessrouter/harnessr
81,481スターと11,203スター──MiniMax公式より大きい「個人製Agent Skills」を2つ確認するの記事画像
検証09.03読了13

81,481スターと11,203スター──MiniMax公式より大きい「個人製Agent Skills」を2つ確認する

出典 ─ GitHub: Leonxlnx/taste