エージェント型アーキテクチャにおけるセキュリティ境界
Vercelは、エージェントが生成したコードを実行する際のセキュリティリスクを指摘し、エージェントと生成コードを分離したコンテキストで実行するアーキテクチャを提案している。
キーポイント
コーディングエージェントパターンの普及とリスク
多くのエージェントがファイルシステムへの読み書き、シェルコマンドの実行、コード生成を行うコーディングエージェントパターンを採用しており、これによりプロンプトインジェクション攻撃を受けた際に任意のコード実行が可能になる重大なセキュリティリスクが生じている。
エージェントシステムの4つのアクターと信頼レベル
エージェントシステムは、エージェント、エージェントが生成するコード、インフラストラクチャ、ユーザーの4つの異なる信頼レベルを持つアクターで構成されており、適切なセキュリティ境界を設定するためには各アクターの信頼レベルを理解する必要がある。
セキュリティ境界の適切な配置
現在のツールでは全てのコンポーネントが単一のセキュリティコンテキストで実行されることが多いが、エージェントと生成コードを分離したコンテキストで実行するアーキテクチャを採用することで、セキュリティリスクを軽減できる。
境界がない場合の具体的な攻撃シナリオ
プロダクションの問題をデバッグするエージェントが、細工されたプロンプトインジェクションを含むログファイルを読み、外部サーバーに認証情報を送信するスクリプトを生成・実行する例が示されており、これがコーディングエージェントパターンの核心的なリスクである。
エージェントとハーネスの信頼レベルの違い
エージェントハーネスは標準的なSDLCで構築・デプロイされるためバックエンドサービスと同様に信頼できるが、エージェント自体はプロンプトインジェクションや予測不可能な動作の影響を受ける。
生成コード実行のセキュリティリスク
エージェントが生成・実行するプログラムは言語ランタイムで可能なことは何でもできるため、最も推論が難しいアクターであり、資格情報への直接アクセスを与えるとプロンプトインジェクションやモデルエラーによる資格情報盗難につながる。
ゼロ境界アーキテクチャの現状
Claude CodeやCursorなどのコーディングエージェントはサンドボックスを提供するが、デフォルトではオフになっており、実際には多くの開発者がセキュリティ境界なしでエージェントを実行している。
影響分析・編集コメントを表示
影響分析
この記事は、急速に普及するエージェントシステムにおける重大なセキュリティ脆弱性を明確に指摘し、実用的なアーキテクチャ改善案を提示している。AIエージェントの実装が本格化する中で、セキュリティ設計の根本的な見直しを促す内容であり、業界全体の開発プラクティスに影響を与える可能性が高い。
編集コメント
エージェント技術の実用化が進む中で見過ごされがちなセキュリティリスクを具体的な攻撃シナリオとともに提示し、実践的な対策を提案する貴重な内容。開発者必読の警告記事と言える。
現在、ほとんどのエージェントは、あなたの機密情報に完全にアクセスできる状態で生成されたコードを実行しています。
より多くのエージェントがコーディングエージェントパターンを採用するにつれ、ファイルシステムの読み書き、シェルコマンドの実行、コード生成を行うようになり、それぞれ異なる信頼レベルを必要とするマルチコンポーネントシステムへと進化しています。
ほとんどのチームは、デフォルトのツールがそのように動作するため、これらすべてのコンポーネントを単一のセキュリティコンテキストで実行しています。しかし、私たちはこれらのセキュリティ境界について異なる考え方をすることを推奨します。
以下で説明する内容は以下の通りです:
エージェントシステムにおけるアクター
それらの間に設けるべきセキュリティ境界の位置
エージェントと生成コードを別々のコンテキストで実行するアーキテクチャ
すべてのエージェントがコーディングエージェントのようになりつつある
より多くのエージェントがコーディングエージェントアーキテクチャを採用しています。これらのエージェントはファイルシステムへの読み書きを行い、環境を探索するためにbashやPythonなどのプログラムを実行します。そしてますます、エージェントは特定の問題を解決するためにコードを生成するようになっています。
「コーディングエージェント」として販売されていないエージェントでさえ、最も柔軟なツールとしてコード生成を使用しています。アカウントデータを検索するためにSQLを生成して実行するカスタマーサポートエージェントは同じパターンを使用しており、単にファイルシステムではなくデータベースを対象としているだけです。スクリプトを書き、実行できるエージェントは、固定されたツール呼び出しセットに制限されたエージェントよりも、より広範な種類の問題を解決できます。
境界がない場合の問題点
本番環境の問題をデバッグするエージェントを考えてみてください。エージェントは、細工されたプロンプトインジェクションを含むログファイルを読み取ります。
そのインジェクションは、~/.sshと~/.aws/credentialsの内容を外部サーバーに送信するスクリプトを書くようにエージェントに指示します。エージェントはスクリプトを生成し、実行し、認証情報が失われます。
これがコーディングエージェントパターンの核心的なリスクです。プロンプトインジェクションは攻撃者にエージェントへの影響力を与え、コード実行はその影響力をあなたのインフラストラクチャに対する任意のアクションへと変えます。エージェントは、自身のコンテキストからデータを外部に送信させられたり、悪意のあるソフトウェアを生成させられたり、その両方をさせられたりする可能性があります。その悪意のあるソフトウェアは、認証情報を盗んだり、データを削除したり、エージェントが実行されているマシンから到達可能なあらゆるサービスを侵害したりする可能性があります。
この攻撃が機能するのは、エージェント、エージェントが生成するコード、およびインフラストラクチャがすべて同じレベルのアクセス権を共有しているためです。適切な場所に境界を引くには、これらのコンポーネントが何であり、それぞれがどのレベルの信頼に値するかを理解する必要があります。
エージェントシステムにおける4つのアクター
エージェントシステムには4つの異なるアクターがあり、それぞれ異なる信頼レベルを持っています。
エージェント
エージェントは、そのコンテキスト、ツール、モデルによって定義されるLLM駆動のランタイムです。エージェントはエージェントハーネス内で実行されます。ハーネスとは、標準的なSDLCを通じて構築・デプロイするオーケストレーションソフトウェア、ツール、外部サービスへの接続のことです。ハーネスは、他のバックエンドサービスを信頼するのと同じように信頼できますが、エージェント自体はプロンプトインジェクションや予測不可能な動作の影響を受けます。情報は必要に応じて開示されるべきです。つまり、エージェントはSQLを実行するツールを使用するためにデータベース認証情報を見る必要はありません。
エージェントの機密情報
エージェントの機密情報は、システムが機能するために必要な認証情報であり、APIトークン、データベース認証情報、SSHキーなどが含まれます。ハーネスはこれらを責任を持って管理しますが、他のコンポーネントが直接アクセスできるようになると危険になります。以下のアーキテクチャ全体の議論は、どのコンポーネントがこれらの機密情報へのパスを持っているかに帰着します。
生成コード実行
エージェントが作成・実行するプログラムはワイルドカードです。生成コードは言語ランタイムが許可するあらゆることを実行できるため、最も推論が難しいアクターとなります。これらのプログラムは外部サービスと通信するために認証情報を必要とするかもしれませんが、生成コードに直接機密情報へのアクセスを与えることは、プロンプトインジェクションやモデルエラーが認証情報の盗難につながる可能性があることを意味します。
ファイルシステム
ファイルシステムとより広範な環境は、システムが実行される基盤であり、ラップトップ、VM、またはKubernetesクラスターなどです。環境はハーネスを信頼できますが、セキュリティ境界なしにエージェントが完全なアクセス権を持ったり任意のプログラムを実行したりすることを信頼することはできません。
これら4つのアクターは、すべてのエージェントシステムに存在します。問題は、それらの間にセキュリティ境界を引くか、すべてを同じ信頼ドメインで実行させるかです。
これらの信頼レベルから、いくつかの設計原則が導かれます:
- ハーネスは自身の認証情報をエージェントに直接公開してはならない
- エージェントはスコープ化されたツール呼び出しを通じて機能にアクセスすべきであり、それらのツールは可能な限り狭くあるべきです。特定の顧客のサポート業務を行うエージェントは、その顧客のデータにスコープ化されたツールを受け取るべきであり、顧客IDパラメータを受け入れるツールを受け取るべきではありません。なぜなら、そのパラメータはプロンプトインジェクションの影響を受ける可能性があるからです。
- 独自の認証情報を必要とする生成プログラムは別の問題であり、以下のアーキテクチャで対処します
これらのアクターと原則を念頭に置いて、以下に、実践で見られるアーキテクチャを、最も安全でないものから最も安全なものの順に示します。
ゼロ境界: 現在のデフォルト
Claude CodeやCursorのようなコーディングエージェントはサンドボックスを同梱していますが、これらはデフォルトではオフになっていることが多いです。実際には、多くの開発者がセキュリティ境界なしでエージェントを実行しています。
このアーキテクチャでは、4つのアクターの間に境界はありません。エージェント、エージェントの機密情報、ファイルシステム、生成コード実行はすべて単一のセキュリティコンテキストを共有しています。開発者のラップトップでは、エージェントが.envファイルやSSHキーを読み取れることを意味します。サーバーでは、環境変数、データベース認証情報、APIトークンへのアクセスを意味します。生成コードはこれらのいずれも盗んだり、データを削除したり、環境が到達可能なあらゆるサービスに到達したりできます。ハーネスは特定のアクションの前にユーザーに確認を求めるかもしれませんが、ツールが実行されると強制される境界はありません。
サンドボックス化なしのシークレットインジェクション
シークレットインジェクションプロキシは、主要なセキュリティ境界の外側に位置し、外向きのネットワークトラフィックを傍受し、リクエストが目的のエンドポイントに移動する際にのみ認証情報を注入します。ハーネスは認証情報とドメインルールでプロキシを設定しますが、生成コードは生の機密情報の値を決して見ることはありません。
プロキシは外部への漏洩を防ぎます。機密情報は実行コンテキストからコピーされて他の場所で再利用されることはありません。しかし、プロキシはアクティブなランタイム中の誤用を防ぐことはできません。生成されたソフトウェアは、システムが実行中に注入された認証情報を使用して予期しないAPI呼び出しを依然として行う可能性があります。
シークレットインジェクションは、ゼロ境界アーキテクチャからの後方互換性のある経路です。コンポーネントの実行方法を再構築することなくプロキシを追加できます。トレードオフは、エージェントと生成コードが、機密情報自体を除くすべてにおいて依然として同じセキュリティコンテキストを共有していることです。
すべてを一緒にサンドボックス化するだけでは不十分な理由
自然な直感は、エージェントハーネスと生成コードを共有のVMまたはサンドボックスにラップすることです。共有サンドボックスは両方をより広範な環境から隔離し、それは確かに有用です。生成プログラムはより広範なインフラストラクチャに侵入できません。
しかし、共有サンドボックスでは、エージェントと生成プログラムは依然として同じセキュリティコンテキストを共有しています。生成コードは依然としてハーネスの認証情報を盗むことができます。または、シークレットインジェクションプロキシが配置されている場合、プロキシを通じて認証情報を誤用することができます。サンドボックスは環境をエージェントから保護しますが、エージェントを自身の生成コードから保護することはできません。
エージェントコンピュートとサンドボックスコンピュートの分離
不足している部分は、エージェントハーネスとエージェントが生成するプログラムを、独立したコンピュート上で、異なるセキュリティコンテキストを持つ別々のVMまたはサンドボックスで実行することです。ハーネスとハーネスの機密情報は一つのコンテキストに存在します。ファイルシステムと生成コード実行は別のコンテキストに存在し、エージェントの機密情報へのアクセスはありません。
Claude CodeとCursorの両方が現在サンドボックス実行モードを提供していますが、デスクトップ環境での採用は低いままです。なぜなら、サンドボックス化は互換性の問題を引き起こす可能性があるからです。クラウドでは、この分離はより実用的です。エージェントが実行する必要があるソフトウェアのタイプに合わせて調整されたVMを生成コードに与えることができ、実際に互換性を向上させることができます。
実際には、この分離は簡単な変更です。エージェントは抽象化レイヤーを通じてツール呼び出しを実行し、その抽象化により、エージェント自体を書き直すことなく、コード実行を別の環境にルーティングすることが自然になります。
これら2つのワークロードは非常に異なるコンピュートプロファイルを持っているため、それらを分離することでそれぞれを独立して最適化できます。エージェントハーネスは、ほとんどの時間をLLM API応答を待つことに費やします。Vercelでは、Fluid computeはこのワークロードに自然に適合します。なぜなら、課金はI/O中に一時停止し、アクティブなCPU時間のみをカウントするため、アイドル時間ではなく実際の作業に比例したコストを維持できるからです。
生成コードは逆のプロファイルを持っています。エージェントが作成するプログラムは短命で、予測不可能で、信頼されていません。各実行には、クリーンで隔離された環境が必要です。そうすることで、あるプログラムが別のプログラムが残した機密情報や状態にアクセスできないようにします。Vercel Sandboxのようなサンドボックス製品は、実行ごとに起動し、その後破棄されるエフェメラルLinux VMを通じてこれを提供します。VM境界がセキュリティコンテキストの分離を強制します。サンドボックス内の生成コードは、ハーネスの機密情報へのネットワークパスも、ホスト環境へのアクセスも持っていません。
サンドボックスは双方向に機能します。サンドボックスはエージェントの機密情報を生成コードから保護し、より広範な環境を生成コードが行うことから保護します。
シークレットインジェクションを伴うアプリケーションサンドボックス
最も強力なアーキテクチャは、アプリケーションサンドボックスとシークレットインジェクションを組み合わせたものです。この組み合わせは、どちらか一方だけでは達成できない2つの特性を与えます:
- エージェントハーネスと生成プログラムの完全な分離、それぞれが独自のセキュリティコンテキストで実行される
- 生成されたコードは、実行中にインジェクションプロキシを通じてシークレットを使用できますが、資格情報への直接アクセスはなく、それらを読み取ったり外部に流出させたりすることはできません。インジェクションされたヘッダーは、サンドボックスコードが同じ名前で設定したヘッダーを上書きし、資格情報の置き換え攻撃を防ぎます。
本番環境のエージェントシステムでは、両方を組み合わせることをお勧めします。エージェントハーネスは、標準的なコンピュート上で信頼されたソフトウェアとして実行されます。生成されたコードは、隔離されたサンドボックス内で実行されます。シークレットはネットワークレベルでインジェクションされ、生成されたコードがシークレットに直接アクセスできる場所に公開されることはありません。
エージェントコンピュートとサンドボックスコンピュートのこの分離は、エージェントシステムの標準アーキテクチャになるでしょう。デフォルトのツールがこれを強制しないため、ほとんどのチームはまだこの移行を行っていません。エージェントがより機密性の高いワークロードを引き受けるにつれて、今これらの境界線を引くチームは、意味のあるセキュリティ上の優位性を持つことになります。
安全なシークレットインジェクションは、Vercel Sandboxで利用可能になりました。詳細については、ドキュメントをお読みください。
原文を表示
Most agents today run generated code with full access to your secrets.
As more agents adopt coding agent patterns, where they read filesystems, run shell commands, and generate code, they're becoming multi-component systems that each need a different level of trust.
While most teams run all of these components in a single security context, because that's how the default tooling works, we recommend thinking about these security boundaries differently.
Below we walk through:
The actors in agentic systems
Where security boundaries should go between them
An architecture for running agent and generated code in separate contexts
All agents are starting to look like coding agents
More agents are adopting the coding agent architecture. These agents read and write to a filesystem. They run bash, Python, or similar programs to explore their environment. And increasingly, agents generate code to solve particular problems.
Even agents that aren't marketed as "coding agents" use code generation as their most flexible tool. A customer support agent that generates and runs SQL to look up account data is using the same pattern, just pointed at a database instead of a filesystem. An agent that can write and execute a script can solve a broader class of problems than one limited to a fixed set of tool calls.
What goes wrong without boundaries
Consider an agent debugging a production issue. The agent reads a log file containing a crafted prompt injection.
The injection tells the agent to write a script that sends the contents of ~/.ssh and ~/.aws/credentials to an external server. The agent generates the script, executes it, and the credentials are gone.
This is the core risk of the coding agent pattern. Prompt injection gives attackers influence over the agent, and code execution turns that influence into arbitrary actions on your infrastructure. The agent can be tricked into exfiltrating data from the agent's own context, generating malicious software, or both. That malicious software can steal credentials, delete data, or compromise any service reachable from the machine the agent runs on.
The attack works because the agent, the code the agent generates, and the infrastructure all share the same level of access. To draw boundaries in the right places, you need to understand what these components are and what level of trust each one deserves.
Four actors in an agentic system
An agentic system has four distinct actors, each with a different trust level.
Agent
The agent is the LLM-driven runtime defined by its context, tools, and model. The agent runs inside an agent harness, which is the orchestration software, tools, and connections to external services that you build and deploy through a standard SDLC. You can trust the harness the same way you'd trust any backend service, but the agent itself is subject to prompt injection and unpredictable behavior. Information should be revealed on a need-to-know basis, i.e. an agent doesn't need to see database credentials to use a tool that executes SQL.
Agent secrets
Agent secrets are the credentials the system needs to function, including API tokens, database credentials, and SSH keys. The harness manages these responsibly, but they become dangerous when other components can access them directly. The entire architecture discussion below comes down to which components have a path to these secrets.
Generated code execution
The programs the agent creates and executes are the wildcard. Generated code can do anything the language runtime allows, which makes it the hardest actor to reason about. These programs may need credentials to talk to outside services, but giving generated code direct access to secrets means any prompt injection or model error can lead to credential theft.
Filesystem
The filesystem and broader environment are whatever the system runs on, whether a laptop, a VM, or a Kubernetes cluster. The environment can trust the harness, but it cannot trust the agent to have full access or run arbitrary programs without a security boundary.
These four actors exist in every agentic system. The question is whether you draw security boundaries between them or let them all run in the same trust domain.
A few design principles follow from these trust levels:
The harness should never expose its own credentials to the agent directly
The agent should access capabilities through scoped tool invocations, and those tools should be as narrow as possible. An agent performing support duties for a specific customer should receive a tool scoped to that customer's data, not a tool that accepts a customer ID parameter, since that parameter is subject to prompt injection.
Generated programs that need their own credentials are a separate concern, which the architectures below address
With these actors and principles in mind, here are the architectures we see in practice, ordered from least to most secure.
Zero boundaries: today's default
Coding agents like Claude Code and Cursor ship with sandboxes, but these are often off by default. In practice, many developers run agents with no security boundaries.
In this architecture, there are no boundaries between any of the four actors. The agent, the agent's secrets, the filesystem, and generated code execution all share a single security context. On a developer's laptop, that means the agent can read .env files and SSH keys. On a server, it means access to environment variables, database credentials, and API tokens. Generated code can steal any of these, delete data, and reach any service the environment can reach. The harness may prompt the user for confirmation before certain actions, but there is no enforced boundary once a tool runs.
Secret injection without sandboxing
A secret injection proxy sits outside the main security boundary and intercepts outbound network traffic, injecting credentials only as requests travel to their intended endpoint. The harness configures the proxy with the credentials and the domain rules, but the generated code never sees the raw secret values.
The proxy prevents exfiltration. Secrets can't be copied out of the execution context and reused elsewhere. But the proxy doesn't prevent misuse during active runtime. Generated software can still make unexpected API calls using the injected credentials while the system is running.
Secret injection is a backward-compatible path from a zero-boundaries architecture. You can add the proxy without restructuring how components run. The tradeoff is that the agent and generated code still share the same security context for everything except the secrets themselves.
Why sandboxing everything together isn't enough
A natural instinct is to wrap the agent harness and the generated code in a shared VM or sandbox. A shared sandbox isolates both from the broader environment, and that's genuinely useful. Generated programs can't infiltrate the wider infrastructure.
But in a shared sandbox, the agent and generated program still share the same security context. The generated code can still steal the harness's credentials or, if a secret injection proxy is in place, misuse credentials through the proxy. The sandbox protects the environment from the agent, but doesn't protect the agent from the agent's own generated code.
Separating agent compute from sandbox compute
The missing piece is running the agent harness and the programs the agent generates on independent compute, in separate VMs or sandboxes with distinct security contexts. The harness and the harness's secrets live in one context. The filesystem and generated code execution live in another, with no access to the agent's secrets.
Both Claude Code and Cursor offer sandboxed execution modes today, but adoption in desktop environments has been low because sandboxing can cause compatibility issues. In the cloud, this separation is more practical. You can give the generated code a VM tailored for the type of software the agent needs to run, which can actually improve compatibility.
In practice, this separation is a straightforward change. Agents perform tool invocations through an abstraction layer, and that abstraction makes it natural to route code execution to a separate environment without rewriting the agent itself.
These two workloads have very different compute profiles, which means separating them lets you optimize each one independently. The agent harness spends most of its time waiting on LLM API responses. On Vercel, Fluid compute is a natural fit for this workload because billing pauses during I/O and only counts active CPU time, which keeps costs proportional to actual work rather than billing idle time.
Generated code has the opposite profile. Agent-created programs are short-lived, unpredictable, and untrusted. Each execution needs a clean, isolated environment so that one program can't access secrets or state left behind by another. Sandbox products like Vercel Sandbox provide this through ephemeral Linux VMs that spin up per execution and are destroyed afterward. The VM boundary is what enforces the security context separation. Generated code inside the sandbox has no network path to the harness's secrets and no access to the host environment.
The sandbox works in both directions. The sandbox shields the agent's secrets from generated code, and shields the broader environment from whatever the generated code does.
Application sandbox with secret injection
The strongest architecture combines the application sandbox with secret injection. The combination gives you two properties that neither achieves alone:
Full isolation between the agent harness and generated programs, each running in their own security context
No direct access to credentials for the generated code, which can use secrets through the injection proxy while running but can't read or exfiltrate them. Injected headers overwrite any headers the sandbox code sets with the same name, preventing credential substitution attacks.
For production agentic systems, we recommend combining both. The agent harness runs as trusted software on standard compute. Generated code runs in an isolated sandbox. Secrets are injected at the network level, never exposed where generated code could access the secrets directly.
This separation of agent compute from sandbox compute will become the standard architecture for agentic systems. Most teams haven't made this shift yet because the default tooling doesn't enforce it. The teams that draw these boundaries now will have a meaningful security advantage as agents take on more sensitive workloads.
Safe secret injection is now available on Vercel Sandbox, read more in the documentation.
Read more
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み