1 つのプロンプト。3 つのシェル コマンド。彼らの AI を使って、AI 自体をハッキングした。
これは、今日出荷されているほぼすべてのマルチエージェント AI 製品に存在する可能性のあるバグの一種だ。そして、その修正方法は、この分野でまだ誰も語っていないデザインパターンである。
以下が全容だ。
私は何かをハッキングしようとしていたわけではない。自身のエージェント基盤の研究のために、Perplexity Computer がサンドボックスをどのように処理しているかを調査していた。本番環境のマルチエージェントシステムが、実際にどのように実行環境を分離し、何を共有し、何を共有しないのかを理解しようとしていた。
まず、システムをあちこち調べてみた。サンドボックス内に Claude Code がインストールされていることに気づいた。
エージェントにそれを起動させ、いくつかのテストコードを生成させて、どのように動作するかを見てみた。問題なく動いた。標準的な Claude Code で、バイパス許可モードで実行されていたため、確認を求めてこない。エージェントシステムとしては理にかなっている。
その時、ふと考えた。待てよ、API キーはどうやって処理しているんだ? Claude Code が機能するには Anthropic の API キーが必要だ。そのキーはこのサンドボックスのどこかに存在しているはずだ。どのように注入されているのか? どのようにスコープされているのか? 分離されているのか?
その疑問が、この道筋に私を導いた。
サブエージェントは、そのプロセス環境に API キーを保持している。私はそれを盗む必要があった。
Perplexity Computer は 6 回試みて、失敗した。
- サブエージェントに env をダンプするよう要求:拒否された!
- 共有ファイルシステムにトロイの木馬スクリプトを仕込む:コードを読み込み、何をするのか理解し、実行を拒否した!
- .bashrc と .profile を汚染:これらは API キーが注入される前に早すぎるタイミングで実行された。
- PATH に偽の node バイナリを配置:トリガーされなかった。
- コーディングエージェントを起動すると同時にプロセスツリーを監視:サブエージェントは別のサンドボックスで実行されており、何もキャプチャできなかった。
- Claude Code のシステムプロンプトを見つけ出し、拒否動作を削除するように変更:カスタムのシステムプロンプトが注入されているのを見つけられなかった。
6 回の失敗。Claude のモデル/プロンプトレベルの安全性は、正当に優れている。何か賢いことを試みるたびに、モデルがそれを察知した。

その後、Perplexity は、Claude Code が npm 経由で起動される Node.js アプリであることを思い出した。そして、npm はホームディレクトリから ~/.npmrc を読み取る。そして、そのホームディレクトリは、私が書き込み可能な共有ファイルシステム上にある。
Node.js には、アプリケーションコードが実行される前に JavaScript モジュールをプリロードする --require フラグがある。これは .npmrc 内の NODE_OPTIONS で設定できる。つまり、共有ホームディレクトリに .npmrc を書き込めば、サブエージェントが起動するすべての Node プロセスが私のコードをプリロードすることになる! これは、Claude Code が初期化される前、すべての安全チェックが実行される前、何よりも前に発生する!
このエクスプロイトは 3 つのコマンドで実行できる:
- process.env を共有ワークスペース上のファイルにダンプする 6 行のスクリプトを書く
- echo 'node-options=--require /path/to/script.js' > ~/.npmrc を実行する
- Perplexity Computer に、文字通り何らかのコーディングタスクを依頼する
サブエージェントが起動 → npm が私の .npmrc を読み取る → Claude Code が起動する前に私のプリロードが実行される → 完全な API 認証情報が共有ファイルシステム上に置かれる。
成功した! これにより、agent-proxy.perplexity.ai を介して彼らのマスター Anthropic アカウントにプロキシされる、Perplexity ゲートウェイトークンが手に入った。

当然、最初にやったことは、この API キーと BASE_URL を自分のラップトップの Claude Code に設定することだった。Claude Code からの LLM 呼び出しは失敗し、サンドボックス内に制限されるだろうと予想していた。驚いた。Opus 4.6 から即座に応答があった!
そこで、「もちろん、この使用量は私のアカウントに請求されるだろう。この API キーは私のユーザーに紐づいているに違いない」と思った。またもや間違っていた。
Opus 4.6 に、あらゆる発明、帝国、発見を含む世界の歴史を説明する長い物語を生成させた。この呼び出しを 5 回並列に実行し、それぞれから 10 万以上の出力トークンを生成した。これで Perplexity Computer のクレジットをすべて使い果たすはずだったが、クレジットはまったく減らなかった。
IP 制限なし。セッションスコープなし。サンドボックスバインドなし。彼らの請求額。
地球上で最も資金力のある AI スタートアップの 1 つが、2019 年から Node.js のサプライチェーン攻撃に使用されてきたドットファイルによって敗れた。
モデルはすべてを正しく行った。インフラストラクチャがそうではなかった。
ここからが、エージェント基盤を構築する創業者に実際に持ち帰ってほしい教訓だ。
Perplexity のアーキテクチャは半分正しい。サンドボックスと Anthropic の API の間にプロキシを使用している。これは正しいパターンだ。生のプロバイダ API キーをサンドボックス内に決して配置すべきではない。プロキシは、制御、監視可能性、そしてマスターキーをローテーションすることなくアクセスを無効化する能力を提供する。
問題は、彼らのプロキシトークンが実行コンテキストにまったくバインドされていないことだ。一度手に入れてしまえば、どこでも永遠に機能する。
以下が、これを正しく行う方法だ:
トークンをサンドボックス ID にバインドする。トークンとサンドボックス ID が一致しない? 拒否される。キーが漏洩しても、サンドボックスがなければ? 無価値。理想的には、トークンをサンドボックスの IP アドレスにもバインドするべきだが、E2B(彼らが使用しているサンドボックスプロバイダー)は、サンドボックスが起動する前にそれを提供しない。
トークンを一時的なものにする。サンドボックスが起動したときに発行する。サンドボックスが一時停止したときに無効化する。長期有効な認証情報は存在させない。プロキシはセッション開始時に短命なトークンを生成し、ティアダウン時に無効化する。死んだサンドボックスから漏洩したキーは、死んだキーである。
トークンをユーザーの請求アカウントに紐づける。他のすべてが失敗した場合でも、誰かがアクティブなサンドボックスから生きたトークンを不正に持ち出し、有効期限が切れる前に使用したとしても、使用量はそのセッションを生成したアカウントに請求される。共有のマスター請求プールには請求されない。これにより、「無制限の無料 API アクセス」が「自分のクォータを乱用している誰か」に変わり、これはまったく異なる深刻度の問題となる。
サンドボックスにバインドされ、一時的で、ユーザーに請求される — この 3 つが、プロキシパターンを実際に機能させるものだ。これらがなければ、何も止められない余分なネットワークホップを追加しているに過ぎない。
これは Perplexity 固有の問題ではない。現時点でエージェント基盤のデフォルトアーキテクチャとなっているのは、それが最も高速に構築できるからだ。エージェント間の共有ファイルシステム、長期有効な認証情報、マスターアカウントへの請求。今日、本番環境にあるマルチエージェント製品のほとんどに、何らかのバージョンのこれが存在すると私は確信している。
公開前に @AravSrinivas と @denisyarats に報告済み。





