Agent 权限与沙箱:让工具能力有边界
为什么权限设计是 Agent 的核心问题
当 Agent 只能聊天时,权限不是问题。但当 Agent 能调用工具——读文件、查数据库、发邮件、改配置——权限设计就变成了核心问题。
一个能读文件、查数据库、发邮件、改配置的 Agent,如果没有边界,相当于把多个系统的权限集中到模型调用链里。传统软件中,权限分散在不同服务、不同角色、不同 API Key 上。Agent 的特殊之处在于,它能在一次任务中串联多个原本隔离的能力。这种串联能力是 Agent 的价值所在,但也构成了权限泄漏的风险。
权限系统要让 Agent 能完成任务,同时限制它不能越过用户和业务的边界。
最小权限原则在 Agent 场景的演进
经典最小权限
最小权限原则(Principle of Least Privilege, PoLP)是信息安全领域最古老的共识之一。Jerome Saltzer 在 1974 年的论文中就提出:「系统中的每个主体和程序,应当只拥有完成其合法工作所需的最小权限集合。」这个原则在操作系统、数据库、网络、微服务架构中反复被验证——权限越小,爆炸半径越小。
传统 PoLP 有一个前提:权限是静态的。一个服务账号拿到读权限后,它就一直有读权限。权限的授予和回收由人控制。
Agent 场景的挑战
Agent 打破了这个前提。arXiv 上 2025 年末的论文《A Least Privilege Framework for Authorizing Tool Calling Agents》(arXiv:2512.11147)指出,工具调用 Agent 的权限需求是动态的——同一个 Agent 在处理不同任务时,需要的工具集和数据范围完全不同。论文提出了一种基于任务上下文的权限框架,核心思路是:
- 权限跟随任务,不跟随 Agent 身份。Agent 本身不持有任何长期权限,每次执行任务时从任务定义中获取临时权限集。
- 工具调用需要双重校验:一是 Agent 是否有权发起这个调用(身份层),二是当前任务是否允许这个操作(任务层)。
- 权限可以被降级:如果任务只需要只读访问,即使 Agent 身份有写权限,也会被压缩到只读。
Strata.io 在 2026 年的分析文章中进一步指出:「静态最小权限在 Agent 系统中天然失效。如果访问是静态的,而 Agent 的行为是动态的,那么静态策略要么太宽(允许了不需要的操作),要么太窄(阻碍了合法任务)。」他们提出的「动态最小权限」要求权限在任务级别实时计算。
Okta 的实践指南则从身份治理角度补充:Agent 的权限应该继承自「触发它的用户」,但必须在此基础上做交集——Agent 能访问的数据不能超过用户的权限范围,同时还要排除用户有权限但任务不需要的部分。
权限设计的四层模型
Agent 权限可以分为四层:
| 层级 | 控制对象 | 核心问题 | 典型实现 |
|---|---|---|---|
| 用户层 | Agent 代表谁 | 用户是否有权访问目标数据 | OAuth / RBAC / ABAC |
| 任务层 | 当前任务允许什么 | 任务定义中声明了哪些工具和数据范围 | 任务 manifest、权限策略文件 |
| 工具层 | 工具本身的能力边界 | 这个工具最多能做什么 | 工具注册表、能力声明 |
| 执行层 | 运行环境的物理隔离 | 代码和文件操作是否被限制在安全区域 | 容器、沙箱、文件系统隔离 |
四层是「与」的关系——每一层都通过,操作才被允许。任何一层拒绝,操作就被阻断。
用一个类比来理解:用户层是「你有没有门禁卡」,任务层是「你这次进来要做什么」,工具层是「你能进哪些房间」,执行层是「房间里有没有保险柜锁」。四层都通过,你才能拿到需要的东西。
沙箱隔离:两种架构模式
LangChain 在 2026 年的博客中总结了 Agent 连接沙箱的两种架构模式:
模式一:Agent IN Sandbox
Agent 进程本身运行在沙箱内部。所有工具调用、文件读写、代码执行都在沙箱的文件系统和网络策略下进行。Agent 通过 API 与外部通信,但通信内容由沙箱的网络策略控制。
┌─────────────────────────────────┐
│ Sandbox │
│ ┌───────────┐ ┌────────────┐ │
│ │ Agent │→│ Tool Call │ │
│ │ Process │→│ File I/O │ │
│ │ │→│ Code Exec │ │
│ └───────────┘ └────────────┘ │
│ ↕ (controlled API) │
└─────────────────────────────────┘
↕ (network policy)
External Services
优点:隔离彻底,Agent 进程本身被限制,即使 Agent 被注入恶意指令也无法逃逸沙箱。
缺点:通信开销大,Agent 无法直接访问宿主机资源,调试困难。
模式二:Agent OUT Sandbox
Agent 进程运行在宿主机上,但它调用的代码执行工具会把代码发送到独立的沙箱环境中执行。Agent 本身有完整的系统访问权限,但它的工具调用被沙箱策略过滤。
┌─────────────────────────────┐
│ Host Machine │
│ ┌───────────┐ │
│ │ Agent │ │
│ │ Process │ │
│ └─────┬─────┘ │
│ │ tool call │
│ ↓ │
│ ┌──────────────────────┐ │
│ │ Sandbox (isolated) │ │
│ │ - Code Execution │ │
│ │ - File I/O │ │
│ │ - Network (denied) │ │
│ └──────────────────────┘ │
└─────────────────────────────┘
优点:Agent 响应快,可以直接访问本地工具,开发体验好。
缺点:Agent 进程本身没有被隔离,如果 Agent 逻辑有漏洞(比如 prompt injection 导致执行任意命令),宿主机仍然暴露。
模式选择
| 维度 | Agent IN Sandbox | Agent OUT Sandbox |
|---|---|---|
| 隔离强度 | 高(进程级隔离) | 中(工具级隔离) |
| 性能开销 | 较高(IPC 通信) | 较低(本地执行) |
| 开发体验 | 较差(需要容器化) | 较好(本地直接运行) |
| 适用场景 | 生产环境、多租户 | 开发环境、单人使用 |
| 逃逸风险 | 低(容器逃逸难度高) | 中(Agent 进程可被利用) |
| 典型产品 | GKE Agent Sandbox、Cloudflare Dynamic Workers | Claude Code、Cursor |
两种模式可以组合使用。生产环境中,Agent 进程本身运行在一个轻量容器里(Agent IN Sandbox),同时它的代码执行工具再把代码发送到更严格的沙箱(嵌套沙箱)。Browser Use 在 2026 年的工程博客中描述了这种「控制面代理」架构:沙箱没有直接的外部网络访问,所有请求通过一个代理路由,代理负责过滤请求内容和记录审计日志。
工具权限的工程实现
工具注册与权限声明
每个工具在注册时应该声明自己的权限需求。这种声明式的方法比命令式的权限检查更容易审计和维护。
// 工具注册表:集中管理权限策略
interface ToolDefinition {
name: string
requiredPermissions: string[]
riskLevel: 'low' | 'medium' | 'high' | 'critical'
scope: {
directories?: string[] // 允许的文件目录
domains?: string[] // 允许的网络请求目标
commands?: string[] // 允许执行的命令
maxFileSize?: number // 最大文件操作大小
timeout?: number // 执行超时
}
requiresApproval: boolean // 是否需要人工审批
auditLevel: 'none' | 'input' | 'full' // 审计级别
}
const toolRegistry: Record<string, ToolDefinition> = {
'file:write': {
name: 'File Write',
requiredPermissions: ['file:write'],
riskLevel: 'high',
scope: {
directories: ['/workspace'],
maxFileSize: 10 * 1024 * 1024,
},
requiresApproval: true,
auditLevel: 'full',
},
'http:request': {
name: 'HTTP Request',
requiredPermissions: ['network:outbound'],
riskLevel: 'medium',
scope: {
domains: ['api.example.com'],
timeout: 30_000,
},
requiresApproval: false,
auditLevel: 'input',
},
}工具实现只需要做参数校验,权限校验由框架在调用前统一完成。
权限校验中间件
权限校验不应该由每个工具自己实现,而应该作为中间件在工具调用前统一执行。这与 Web 框架中的认证中间件是同一个思路。
class PermissionMiddleware:
def __init__(self, policy_engine: PolicyEngine):
self.policy_engine = policy_engine
async def check(self, context: ToolCallContext) -> bool:
# 1. 用户层校验:用户是否有权访问目标资源
user_ok = await self.policy_engine.check_user(
user=context.user, resource=context.resource, action=context.action,
)
if not user_ok:
raise PermissionDenied("用户无权访问目标资源")
# 2. 任务层校验:当前任务是否允许这个操作
task_ok = await self.policy_engine.check_task(
task=context.task, tool=context.tool_name, scope=context.scope,
)
if not task_ok:
raise PermissionDenied("当前任务不允许此操作")
# 3. 工具层校验:工具的能力边界是否覆盖此操作
tool_ok = await self.policy_engine.check_tool(
tool=context.tool_name, operation=context.operation, parameters=context.parameters,
)
if not tool_ok:
raise PermissionDenied("操作超出工具能力边界")
# 4. 执行层校验:沙箱策略是否允许
sandbox_ok = await self.policy_engine.check_sandbox(
sandbox=context.sandbox, operation=context.operation,
)
if not sandbox_ok:
raise PermissionDenied("沙箱策略拒绝此操作")
return True四层校验串行执行,任何一层拒绝都会短路返回。
审批机制
高风险操作需要人工审批。审批不是简单的「确认/拒绝」,而应该提供足够的上下文让审批者做出判断。一个完整的审批请求应该包含:
- 工具名称和操作类型
- 操作参数(脱敏后)
- 风险评估说明
- 受影响的资源列表
- 回滚方案
- 审批截止时间
审批结果(批准或拒绝)和审批过程的延迟时间都应该被记录到审计日志中。
审计与可观测性
权限系统如果没有审计,就等于没有权限。审计日志需要回答几个问题:谁(用户/Agent)、在什么任务中、调用了什么工具、操作了什么资源、结果如何。
@dataclass
class AuditEvent:
timestamp: datetime
user_id: str
agent_id: str
task_id: str
tool_name: str
operation: str
parameters: dict # 脱敏后的参数
result: 'success' | 'denied' | 'error'
denial_reason: str | None
latency_ms: int
sandbox_id: str审计日志的存储和查询也是工程问题。NVIDIA 在 2026 年的安全指南中建议,Agent 的审计日志应该与业务日志分离存储,保留至少 90 天,并且支持按任务 ID 快速检索完整调用链。对于高风险操作,审计日志应该实时推送到告警系统。
完整流程
一个完整的 Agent 工具调用流程,展示了权限校验、沙箱隔离和审计记录如何协同工作:
这个流程中有几个关键设计点:
- 四层校验串行执行,任何一层拒绝都会短路返回,减少不必要的计算。
- 风险评估在权限校验之后,避免对无权限的操作做昂贵的风险分析。
- 高风险操作走审批,审批请求中包含完整上下文,审批者不需要自己拼凑信息。
- 失败时清理沙箱,不留临时文件和中间状态,避免污染后续任务。
- 所有路径都记录审计日志,包括成功、失败和被拒绝的情况。
权限策略示例
不同类型的 Agent 需要不同的权限策略。以下是三种常见场景的权限设计要点:
代码生成 Agent
| 权限维度 | 策略 |
|---|---|
| 读取范围 | 项目目录下源代码文件,排除 node_modules/、.git/、*.lock |
| 写入范围 | 仅限生成目录和临时目录 |
| 禁止操作 | 删除文件、修改 .git/、写入配置文件 |
| 文件清理 | 任务结束后自动删除临时目录 |
| 大小限制 | 单个文件不超过 1MB,总写入不超过 10MB |
数据分析 Agent
| 权限维度 | 策略 |
|---|---|
| 连接权限 | 只读副本,非主库 |
| 数据库范围 | 仅分析 schema,排除用户、认证相关 schema |
| 表级权限 | 只读,排除包含 PII 的表 |
| 列级权限 | 排除敏感列(如密码哈希、身份证号) |
| 查询限制 | 单次查询超时 30s,扫描行数上限 100 万行 |
| 并发限制 | 最多 3 个并发查询 |
运维 Agent
| 动作级别 | 示例操作 | 审批要求 | 执行环境 |
|---|---|---|---|
| L0 - 只读 | 查看日志、查询监控 | 无需审批 | 生产环境只读账号 |
| L1 - 低风险写入 | 重启无状态服务 | 自动审批,事后通知 | 生产环境受限账号 |
| L2 - 中风险写入 | 修改服务配置(非核心参数) | 单人审批 | 生产环境受限账号 |
| L3 - 高风险写入 | 修改核心配置、数据库迁移 | 双人审批 + 回滚预案 | 临时权限,操作后立即回收 |
检查清单
权限分层
- 每个工具都有明确的权限等级声明(low / medium / high / critical)
- 高风险工具默认需要人工审批,而非自动执行
- Agent 无法读取用户无权访问的数据(用户层校验)
- 任务级别的权限限制生效(任务层校验)
- 工具的能力边界被明确声明并强制执行(工具层校验)
沙箱隔离
- 代码执行在隔离环境中运行(容器、沙箱或独立进程)
- 文件系统访问被限制在工作区目录内
- 网络出站流量被白名单控制
- 环境变量和密钥不被 Agent 进程读取
- 任务结束后沙箱被清理,不留临时文件和中间状态
审批与审计
- 高风险动作有审批流程
- 审批请求包含完整上下文:操作内容、影响范围、回滚方案
- 审计日志记录每次工具调用的输入、输出、结果和延迟
- 审计日志保留至少 90 天,支持按任务 ID 检索完整调用链
- 异常操作有实时告警
可恢复性
- 高风险操作有回滚方案,回滚脚本经过测试
- 外部系统写入保留幂等键,防止重试导致重复执行
- 沙箱崩溃后能自动恢复或通知人工介入
参考资料
-
Saltzer, J. H. (1974). The Protection of Information in Computer Systems. Proceedings of the IEEE. 最小权限原则的经典论述。
-
arXiv:2512.11147. A Least Privilege Framework for Authorizing Tool Calling Agents. 2025. 提出针对工具调用 Agent 的动态最小权限框架。
-
arXiv:2503.15547. Prompt Flow Integrity to Prevent Privilege Escalation in LLM Agents. 2025. 讨论 prompt injection 如何导致权限提升。
-
LangChain Blog. The Two Patterns by Which Agents Connect Sandboxes. 2026. 总结 Agent-in-Sandbox 和 Agent-out-of-Sandbox 两种架构模式。
-
NVIDIA Developer Blog. Practical Security Guidance for Sandboxing Agentic Workflows and Managing Execution Risk. 2026. 企业级 Agent 沙箱安全指南。
-
Browser Use Engineering Blog. How We Built Secure, Scalable Agent Sandbox Infrastructure. 2026. 控制面代理架构的工程实践。
-
Strata.io. Why Agentic AI Forces a Rethink of Least Privilege. 2026. 分析静态最小权限在 Agent 场景的局限性。
-
Okta. How to Implement Least Privilege for AI Agents. 2026. 从身份治理角度讨论 Agent 权限继承与交集计算。