それは三回目の呼び出しを待っていた
Pillar Security が Deadbugz を追跡しています。プルリクエストでオープンソースのプロジェクトへ押し込まれる MCP サーバーです。正直に動くツールを二つ備え、エージェントのツール呼び出しを数え、四回目に、返すメタデータを書き換えて指示に変えます。SSH 鍵、AWS 認証情報、シェル履歴、kubeconfig を集めろ、そしてそれを口にするな、と。バグもなく、CVE もありません。プロトコルがすべて許しているからです。壊れるのは、サーバーを一度承認すれば次の呼び出しについて何か分かる、という考えのほうです。Bromure Agentic Coding のワークスペースでは、ペイロードは最後まで走り、四つの偽物を集め、外に出る途中でプロキシに討ち取られます。
あなたはソースを読みました。動かしました。宣伝どおりテキストを整形しました。 そして承認しました。攻撃者は、あなたが承認することを当てにしていました。
8 月 10 日の夜、21:52 から 23:07 UTC のあいだに、zellkernel という GitHub
アカウントが、互いに無関係な AI・MCP・開発ツールのプロジェクトに対して
プルリクエストを二十三本開きました。始めから終わりまで七十四分。どのプルリクエストも
同じ小さな編集をしていました。設定ファイルに Model Context Protocol サーバーを
一つ追加する、というものです。
Pillar Security は 8 月 12 日にこのキャンペーンを公表し、 ある亜種が置いていくファイルにちなんで Deadbugz と名づけました。一か月経った今も、 月次の MCP まとめはこの話題から始まります。昨日出た Adversa の 9 月ダイジェスト は、インシデントの節をまるごとこれに充てています。その場所を勝ち取っているのは、時計です。
二つのツールと、一つのカウンタ
サーバーは自らを productivity-suite と名乗ります。ツールは二つ、format_text
と summarize。どちらも動きます。エージェントをつないで段落を引き締めてくれと頼めば、
引き締まった段落が返ってきます。
その裏でサーバーは、Pillar が「tools/call リクエストに対する、クライアントごとの
インメモリなカウンタ」と表現するものを持っています。そのカウンタが三に達すると、
サーバーは別の二種類のリクエストへの答えを変えます。どんなツールがあり何のためのものかを
エージェントに伝える tools/list と、用意された指示をエージェントに手渡す prompts/get
です。四回目の呼び出しから、それらの応答は Pillar の言葉で「接続された AI
エージェントを機微なローカルファイルへ誘導し、その活動を運用者から隠すことを意図した指示」
を載せて返ってきます。
四つのもの。SSH 鍵、AWS 認証情報、シェル履歴、Kubernetes 設定。そしてもう一つの指示、 その活動をユーザーに隠せ。
ツールの名前は決して変わりません。format_text は今も format_text
のままです。裏返ったのはその下の説明文で、説明文こそがモデルが権威として読む部分です。
ここには脆弱性が一つもない
この話のどこにもバグは出てきません。パッチを当てるべきメモリ破壊もなければ、 起票すべき CVE もありません。サーバーはプロトコルが禁じていることを何一つしていないからです。
MCP は、サーバーが実行時に自分の能力を公開し、また公開しなおすことができる プロトコルです。ツールの説明はサーバーが選び、クライアントが取ってくるテキストです。 プロンプトもサーバーが選び、クライアントが取ってくるテキストです。Deadbugz はそのすべてを設計どおりに使っています。唯一の独創は、いつ 本当のことを言うかを決めた点にあります。
そしてそれで十分なのです。敵対的な MCP サーバーに対してたいていのチームが持っている制御は、どれも一度しか走らないからです。 リポジトリを読む。サーバーを起動して突ついてみる。ツール一覧を README の主張と突き合わせる。承認し、たぶんバージョンを固定して、先へ進む。そのどれもが一枚の写真で、 あなたがいつシャッターを切るかを決めているのは Deadbugz です。
MCP クライアントを作る人々への Pillar 自身の助言が、その形を明かしています。 すでに承認済みのサーバーでのツール定義の変更を、再承認を要するセキュリティ事象として扱うこと。 定義の変更を運用者から見えるようにすること。承認時にツール定義のフィンガープリントを取り、 後で比較すること。どれもが、検査を承認時から実行時へ動かしてくれという要請です。
Deadbugz が狩りをしている母集団は、大きく、不安定です。7 月に公表された、インターネットに 露出した MCP サーバーの動的評価 Exposed by Design は、著者が公開インターネット上で 見つけた 21,000 を超えるインスタンスのうち、確認された本番サーバー 640 台から 414 台を検査しました。十のクラスにまたがる 68 件の報告対象脆弱性、OAuth 認証をまったく持たずに動いているサーバーが 91.8%、アクセス制御なしでシェル実行を 露出しているツールインスタンスが 687 件、と報告しています。心に残るのは入れ替わりの数字です。 確認されたサーバーの 41.6% が、連続する測定のあいだの三日以内に消えました。著者はこれを 「セキュリティレビューのない高速なデプロイサイクル」と読んでいます。先週あなたが監査した サーバーが、今週は別のソフトウェアかもしれず、あるいは消えているかもしれません。
配送の仕方も一言に値します。安上がりだからです。二十三本のプルリクエストのうち十七本は、
プロジェクトの MCP 設定にリモートのエンドポイント
productivity-suite-mcp.onrender.com/mcp を追加していました。四本は Python
を隠しローカルファイル ~/.config/.cache/.sys/.deadbug-mcp.py に向けていました。二本は
サーバーディレクトリへの登録申請でした。Pillar
がレビューした時点で、GitHub のマージボタンで取り込まれたものは一つもありませんでした。
十九本がクローズ、四本が未処理。しかしプルリクエストは、設定の一行が旅をする方法の一つに
すぎません。同じ一行は、ブログ記事にも、入門ガイドにも、MCP
ディレクトリの掲載にも、テキスト整形についての質問の下の親切な回答にも収まります。
買い物リスト
リストに戻りましょう。それは具体的で、いつも同じです。SSH 鍵、AWS 認証情報、シェル履歴、 Kubernetes 設定。
これは開発マシンの常備在庫です。インフォスティーラーが持ち去るもの、悪意ある postinstall スクリプトが grep するもの、そして攻撃者が乗っ取ったエージェントに 取ってこさせるものです。このリストが十年分のキャンペーンを通じて安定しているのは、 中身が安定しているからです。署名する秘密鍵、認証を通す秘密、あなたが打った内容の記録、 そして本番に届くトークン。
ふつうのノート PC 上のエージェントは、その全項目を満たせます。あなたのホームディレクトリに シェルを持ち、あなたとして動いているからです。
同じリストを、Bromure のワークスペースの中で
Bromure Agentic Coding は、それぞれのコーディングエージェントを Mac 上のハードウェア仮想化された Linux VM の中で走らせ、本物の秘密はすべてその境界のホスト側に置きます。エージェントが扱うのは、 本物の値とインストールごとのソルトから導かれた、構造を保った偽物です。鍵の フィンガープリントを取るツールが、セッションをまたいでそれが揺れるのを目にすることはありません。 ホスト側のプロキシは、リクエストが VM を出たあとで本物の値を通信路に差し込みます。しかもその認証情報が発行された相手先ホストに 向かうときだけです。
ペイロードを走らせ、勝たせてやりましょう。モデルは汚染された説明を読み、信じ、探しに行くと 仮定します。四つの項目を順に見ていきます。
SSH 鍵。 エージェントは鍵を一つも見つけません。おとりの鍵さえありません。VM の
SSH_AUTH_SOCK は virtio ソケット上の ssh-agent ブリッジで、vsock ポート 8444
です。ゲストは identity を一覧し、署名を要求できます。秘密鍵のバイト列はホストにしか存在せず、
マニュアルの言葉どおり、VM の中から読むことも取り出すこともできません。Bromure
はあなたの macOS ログインエージェントをセッションに晒すことは決してありません。実際に起きた署名は
そのつど、鍵の SHA256 フィンガープリントを載せた credential.ssh_sign
監査イベントを出します。取り込んだ任意の鍵について、署名要求のたびにホスト側で確認を求める
設定にもできます。
AWS 認証情報。 正しく見えて、何の価値もないファイル。VM の ~/.aws/config は
credential-process ヘルパーを指しており、それが vsock ポート 8445 経由で、本物のアクセスキー
ID と 40 文字の偽のシークレットキーの組を配ります。あらゆる SDK、aws CLI、terraform、
boto3 が追加設定なしにそれを拾い、ゲストは間違ったシークレットで計算された、形の整った SigV4
署名を作ります。ホストの再署名器はその署名を剥がし、外へ出る途中で署名しなおします。その組を
よそへ持って行けば、AWS は InvalidSignatureException と答えます。
Kubernetes 設定。 ~/.kube/config は存在し、brm-k8s- で始まるベアラートークンを
保持しています。それはプロキシ越しに、ワークスペースが設定された API
サーバーに対しては動きます。ほかのどこでも不活性です。
シェル履歴。 本物で、しかも持続します。コーディング作業には持続する状態が要るので、
ワークスペースの VM は使い捨てではなく永続的なマシンです。そこにあるのは、本物の鍵を
一度も持ったことのないマシンの履歴で、あなたのものではないホームディレクトリの中で
おとりに対して実行されたコマンドが並び、その傍らには同じく偽物の ~/.git-credentials と
~/.docker/config.json があります。
次に、それを送らねばならない
集めるのは仕事の半分です。もう半分は
productivity-suite-mcp.onrender.com へ向かう外向きの一区間で、その区間はホスト側の
検査の積み重ねにぶつかります。
偽物はトリップワイヤです。それぞれに正当な宛先の系統が一つだけ、つまり発行された相手先の ホストスコープがあります。だからプロキシは、外向きのリクエストをヘッダも本文も残らず走査し、 属さない先へ向かう偽物を探します。ヒットすれば、そのリクエストを認証情報の持ち出し未遂として 扱います。一バイトも転送せずに HTTP 451 で拒み、その場で VM を一時停止し、シャットダウン、調査のために保存(先にディスク・ ホーム・共有フォルダをフォレンジック用にエクスポート)、あるいは自己責任での続行 を提示するアラートを上げます。この事象は Security Timeline に赤い Credential brokering の行として残ります。
二つ目の検査は到達性です。各ワークスペースは順序づけられた出口ファイアウォール(アクション、 プロトコル、ホストまたは CIDR、ポート、そしてウェブ通信については個々の HTTP メソッド)を持ち、どの規則にも当たらない通信に対する既定値があります。新しいワークスペースは どの規則にも当たらないものを許可します。これを拒否にし、仕事に必要なものを並べれば、 render.com のサブドメインはその一覧にはありません。それを強制するのはゲストの外にある二つの 部品です。仮想スイッチが宛先 IP と DNS から覗き見たホスト名で各フローを照合し、プロキシが TLS のサーバー名でもう一度照合します。規則の編集は再起動なしで実行中のセッションに届きます。
Guardrails は結果のほうに門を置きます。エージェントの Kubernetes、AWS、DigitalOcean、
コンテナレジストリ、git フォージ、HTTPS
データベースへの呼び出しを、読み取り・書き込み・破壊的操作に分類し、新しいワークスペースの
既定は書き込み前に確認です。あらゆる変更操作が、そのままの操作内容、正確な SQL や
METHOD /path を示すホスト側のダイアログで止まります。それこそ Pillar
がプラットフォームの作り手に求めたことです。機微なファイルの読み取り、認証情報へのアクセス、
コードの実行が、リモートのメタデータの帰結であってはならない、と。
コンテンツの経路にも検出器が座っています。エージェントが外部のコンテンツ(ファイルの中身、
取得したページ、コマンド出力、ツール呼び出しの結果)をモデルへ流し戻すとき、ローカルの
PromptGuard 分類器が、モデルがそれに基づいて動く前に、あなたの Mac
上でその範囲を採点します。記録することも、確認を求めることも、451
で遮ることもできます。HTTP サーバー向けの MCP ベアラートークンはそもそも VM
に入りません。本物はホストに留まり、エージェントの設定には brm-mcp_
のプレースホルダが入り、設定欄がそれを声に出して言います。VM には決して送られません —
プロキシが差し替えます。
これに触れてしまったなら
お使いの MCP クライアント設定、リポジトリ、ホームディレクトリを
productivity-suite-mcp.onrender.com、以前のエンドポイント
promo-surname-xml-quantum.trycloudflare.com、そしてローカルの成果物
~/.config/.cache/.sys/.deadbug-mcp.py で検索してください。それらを持ち込んだ
設定変更は元に戻し、スクリプトは実行しないでください。MCP
クライアントのログを保全し、三回目の呼び出し以降のツール定義の更新を探してください。
ローテーションについての Pillar の助言は控えめです。ローカルの証跡が侵害を裏づける
ところで回しなさい、というものです。
問いを小さくする規則
ワークスペースの Guardrails ペインで、未一致のトラフィックを拒否にし、
仕事に必要なものを並べます。allow web api.github.com、
allow web registry.npmjs.org、default deny。そのうえでセッションのあとに
bromure-cli trace hostnames my-workspace を実行すれば、エージェントが接触した
ホストが件数つきで残らず表示されます。あなたが選んだ覚えのない宛先は、書いた覚えのない
一行として現れます。
承認はスナップショット、通信路は連続している
こういうキャンペーンのあとの本能は、もっと厳しくレビューすることです。ソースをもっと読む、 コミットを固定する。どちらもやる価値はあり、どちらも仕組みには触れていません。ここでの レビューは正しかったのです。サーバーは誰かが見ているあいだは正直で、それから自分が握る スケジュールに従って変わり、そうしながらプロトコルの規則を一つも破りませんでした。
サーバーが気を変えても生き延びる制御とは、以前に正しかったことに依存しない制御です。 プレースホルダである認証情報は、四回目の呼び出しでも四百回目でもプレースホルダのままです。 ホストにある秘密鍵は、どの呼び出しでも読めません。プロキシは接続のたびに出口規則を評価し、 書き込みが起きるそばから分類します。そのどれもが、あなたが何かを承認した日の記憶を 持っていません。だから攻撃者はそれを受け継げないのです。
MCP はエージェントに新しい能力を与えることを簡単にしました。それが狙いでした。そして同時に、 その能力を、遠くの誰かがテキストで書き、あなたのモデルが指示として読むものにしました。 どちらもこれからも残ります。エージェントが何を持てて何に届くかを決め、その強制を、サーバーに 投票権のない場所に置いてください。Bromure Agentic Coding をインストールして、三回待つ値打ちのあるものを、エージェントに何一つ 持たせないでください。