フックはモデルに届かなかった
8 月 31 日、Token Security が The Hacker News で、ローカルの Claude Code セッション向けに追加された Anthropic の Compliance API エンドポイントを解説しました。これは本物の前進であり、記事は「トランスクリプトがどこで途切れるか」についても正確です。ツールが走る前に発火するフック、ディスク上に置かれたファイル、セッション外で起動されたプロセス、Bedrock や Vertex が提供するものすべて。先週の npm ワームは、その隙間だけで生涯を過ごしました。Bromure Agentic Coding は VM と外界のあいだの線に直接タップを入れるため、記録に残るのは「誰かがモデルに言ったこと」ではなく「実際に起きたこと」です。
トランスクリプトに入りうるのは、誰かがモデルに言ったことだけです。エージェント セッションの面白い半分は、誰も口に出さないほうの半分です。
今年のほとんどの期間、ノート PC 上で Claude Code が何をしていたかを知りたい エンジニアリングマネージャーには、選択肢が二つしかありませんでした。開発者の スクロールバックを読むか、サードパーティのラッパーを買うか。Anthropic の コンプライアンス用エンドポイントは claude.ai と Claude Desktop をカバーしており、 Claude Code はほとんど対象外でした。
それが 8 月 11 日に変わりました。Anthropic はローカルセッション向けに三つの
Compliance API エンドポイントを出荷しました。一つはセッションの一覧、一つは
セッションのメタデータの取得、そして三つ目は
GET /v1/compliance/apps/sessions/local/{session_id}/messages から完全な
トランスクリプトを引き出します。8 月 31 日、Token Security は
それが何を与えてくれるかの解説
を The Hacker News に掲載しました。
あの記事は Token Security がスポンサーですが、それでもログの地平線がどこにあるか について私が読んだなかで最も慎重な説明のひとつです。
三種類のブロックと、その守備範囲
トランスクリプトは三種類のブロックとして届きます。記事の言葉では、
「モデルに伝えられたものはすべて、text、tool_use、tool_result という三つの
ブロック型で記録される。これらを合わせれば、ユーザープロンプト、bash コマンド、
読み書き、さらには MCP コマンドまでカバーされる」。
これはかなりの量です。モデルが選んだシェルコマンドのすべて、読んだファイルの すべて、呼んだ MCP ツールのすべて。「このエージェントは火曜日に何をすると決めたのか」 という問いなら、トランスクリプトが答えてくれます。しかも、調査対象のマシン上の ファイルからではなく、Anthropic のサーバーから答えてくれます。
実際の仕事をしているのは、最初の一節です。モデルに伝えられたものはすべて。
地平線
この境界の外側には四つのものがあり、記事はその四つすべてを名指ししています。
フック。 「フックが最も明確な例だ。ローカルで、モデルの決定と実際にツールが 走ることのあいだで実行され、ツールの実行やプロンプトの送信を止めることができる」。 フックとは開発者のディスク上にあるコードで、モデルが行動を選んでから、その行動が 実際に起きるまでの隙間で発火します。モデルはそれについて何も聞かないので、 トランスクリプトもそれを運びません。
ディスク。 「どちらもディスク上にあるものは見えない。設定ファイル、 インストール済みのスキルやプラグインとその .md ファイル(セッション内で使われた 場合を除く)、あるいはセッション外で起動されたプロセスなど」。インストールして 一度も呼び出していないスキルは何の痕跡も残しませんし、エージェントが一時間前に 起動して忘れたバックグラウンドプロセスも同じです。
他のモデルプロバイダー。 「Anthropic 以外のモデルで Claude Code を動かす場合、 Compliance API のカバレッジはまったく得られない。Anthropic のモデルとのやり取り しか記録しないからだ。Bedrock、Foundry、Google Cloud で動くセッションは対象外に なる」。カバレッジは Anthropic のモデルで止まり、Codex、Gemini CLI、Grok、そして 来四半期にあなたのチームが入れる何かが外れます。
権限の判断。 危険なコマンドに対する開発者の承認や、プロンプト全体を素通し させたバイパスフラグは、コンプライアンス用トランスクリプトではなく OpenTelemetry に落ちます。
これらはすべて正しい挙動です。モデルに錨を下ろしたログは、モデルが見たものを 記録します。次のセキュリティレビューで問うべきなのは、あなたが最も見たいものが その線のモデル側に落ちているかどうかです。
先週のワームはその隙間に住んでいた
四日前、週間ダウンロード数 15 万を超える npm のコードジェネレーターが、 資格情報を盗むコードを配り始めました。私たちは 土曜日にその公開の連鎖を書きました。 見知らぬ人物がプルリクエストにコメントし、プロジェクトのリリースワークフローが 書いた人物を確認しないままそのコメントを読み、署名済みの 10 バージョンが 出ていきました。
そのマルウェアを、もう一方の手にコンプライアンス用トランスクリプトを持って 読み直してください。各ステップがどこに現れるかを追ってみましょう。
エージェントは npm install を実行します。これは tool_use ブロックであり、
トランスクリプトも持っています。その後に続くものはすべて子プロセスです。
第一波はインストールスクリプトをまったく宣言していませんでした。ペイロードは
node-gyp が読むビルド記述 binding.gyp の中、node-gyp が Python で評価する
conditions フィールドに置かれていました。モデルはそれについて一度もターンを
持たず、どのツール呼び出しもそれを名指ししません。ビルドファイルの中の Python 式が、
トランスクリプトがごく普通と記録したその一つのコマンドの孫として走ったのです。
続くスイープは、SSH 鍵、.env ファイル、クラウドの資格情報、レジストリの
トークンを求めて、ホームディレクトリ配下の 150 を超える glob パターンを歩き
回りました。そのどれについても、誰もモデルには尋ねていません。
そして永続化です。到達できるすべてのリポジトリで、ワームは
.claude/settings.json を書き、そこに SessionStart フックを仕込みました。
開発者が Claude Code でそのプロジェクトを開くたびに setup.mjs が走ります。
ディスク上にあり、誰かがモデルに相談する前に発火するフック。四つの死角のうち
二つが一つのファイルに収まっています。この場所を選んだ攻撃者が、ベンダーの
コンプライアンス変更履歴を読んでいたとは、まず考えられません。
敵対的な窓が開いていた時間は合計で 3 時間 11 分。その一部たりとも、モデルには 届いていません。
Bromure はどこにタップを入れるか
Bromure Agentic Coding は、各ワークスペースを Apple Silicon 上の独立した仮想 マシンとして動かし、その VM を出るものはすべて、ハイパーバイザーの Mac 側にある プロキシと仮想スイッチを通ります。スイッチは VM のポート 80 と 443 のフローを プロキシへ迂回させます。設定すべき環境変数はなく、ゲスト側から解除できるものも ありません。したがって記録は、エージェントの協力にも、プロキシの存在を エージェントが知っているかどうかにも依存しません。
トレースレベル Activity only 以上では、すべてのリクエストにメタデータの
レコードが一つ付きます。タイムスタンプ、ホスト、ポート、メソッド、パス、
ステータスコード、レイテンシ、資格情報の差し替え前に測ったリクエストバイト数、
レスポンスバイト数、外へ出る際にプロキシが差し替えた資格情報、そして Bromure が
発行していないベアラートークンをリクエストが運んでいた場合の警告。このレコードは、
リクエストがエージェントから来ようと、postinstall スクリプトから来ようと、
独自に動く MCP サーバーから来ようと、誰かが三時間前に起動して忘れたプロセスから
来ようと、必ず存在します。
Security Timeline ウィンドウ(Window → Security Timeline…)はその隣にあり、
別の問いに答えます。Trace Inspector はエージェントが何を送ったかを教え、
タイムラインは Bromure のエンジンが何を決めたかを教えます。新しい順に並ぶ一つの
時系列テーブルで、色分けは緑が許可、赤がブロック、青が情報。資格情報ブローカー、
ファイアウォール、サプライチェーン、ガードレール、プロンプトインジェクション、
資格情報の使用、上流 TLS。メモリ上には 5,000 行を保持します。永続的なコピーは
~/Library/Application Support/BromureAC/traces/ にある暗号化済みセッション
トレースで、ワークスペースのシークレットと同じキーチェーン鍵で AES-GCM 封印
されています。
同じインストールが、Bromure のワークスペースではこう読めます。
これらの行はどれ一つとして、ペイロードがモデルを通ったことを必要としません。 そしてどれも VM 内のコードから編集できません。それらを書くエンジンは Mac 上で 動いており、ゲストにはそこへ至る経路がないからです。
どのエージェントを走らせても、同じ行が出る
あるチームが Claude Code に標準化します。そこへ誰かが一つのプロジェクトに Codex を持ち込み、プラットフォームチームがデータレジデンシーのために ワークスペースを Bedrock 経由にし、研究者が Grok を走らせ始めます。記事自身の 説明によれば、この四つのうち三つは Compliance API に何も生みません。
TLS のサーバー名を読むプロキシは、四つとも同じように見ます。そして同じ
llm.request、tool.use、command.run、file.read、file.write の各イベントが
そのすべてから出てきます。ベンダーに与えられるのではなく、トラフィックから
引き出されるからです。bromure.io ワークスペースに登録された Mac では、これらは
相互 TLS で組織へ流れます。ファイアウォールの判定ごとの egress.firewall、
おとりの資格情報が発行先ではないホストへ出ていったときの
credential.exfiltration、そしてワークスペースが取得したパッケージごとの
supply_chain.fetch と並んで。最後のものは、サプライチェーンの強制レイヤーを
すべて切っていても発火します。Bromure は「見ること」と「止めること」を分けて
いるからです。このストリームは生のプロンプトを運びません。答えるのは、
エージェントが何をしたかであって、開発者が何を頼んだかではありません。
記事が締めくくる一行
この記事で最も鋭い一文は、カバレッジの話を置き去りにします。「アクティビティ ログだけでは、エージェントのアクセスが正当かどうかは分からない」。
これはどんなログにも当てはまります。だからこそ Bromure のエンジンは、その仕事を 別の観測者に渡さず、自分でタイムラインを書きます。あのウィンドウの赤い行は どれも、すでに起きた決定の記録です。サプライチェーンの行は、エージェントが 決して受け取らなかったパッケージを意味します。ファイアウォールの行は、 決して開かなかった接続を意味します。ガードレールの行は、ホストが 403 で拒否し、 エージェントがただの API エラーとして読んだプッシュであり、資格情報ブローカーの 行は、決して本物の秘密にならなかったおとりです。本物は最初から VM の中に なかったのですから。
ポリシーを決めるのは依然としてあなたです。しかし「このアクセスは正当だったか」に 答えるのは、ワークスペースを設定している最中であって、何週間もあとに行を 読んでいるときではありません。
タップをどこに置くか
コーディングエージェントを少しでも規模を持って動かしているなら、Compliance API を 有効にしてください。四週間前、この面にはほとんど可視性がありませんでした。 一週間分のトランスクリプトは、自分のチームについて知らなかったことを教えて くれるはずです。
そのうえで二つ目の問いを立ててください。トランスクリプトがきれいに見えるマシンを、
あなたはどう扱いますか。Bromure のワークスペースなら、答えはすでに画面上に
あります。ホストを見るには Window → Trace Inspector、判定を見るには
Window → Security Timeline を開くか、bromure-cli trace hostnames を実行して、
そのワークスペースが起動以来つないだドメインをすべて読んでください。
そこに在るために、エージェントが何かを口にする必要はありません。 Bromure Agentic Coding をインストールして、タイムラインを開き、 インストールを一度眺めてみてください。