跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言Agent Runtime工程化安全陈堂会

《Agent Runtime 工程化》第七章 权限与安全边界

能力越大,边界越要清楚。本章谈权限和安全。 Agent 的能力来自工具,风险也来自工具。一个不会调用工具的模型,最多说错话;一个能执行命令、写文件、联网、访问数据库的 Agent,可能造成真实损失。Runtime 的安全目标不是把 Agent 绑住,而是让它在明确边界内做事;越过边界时,停下来请人确认,或者直接拒绝。 安全不是最后加的一层“确认弹窗”。它应该

站点编辑发布于 2026/8/15更新于 2026/9/3061 浏览
《Agent Runtime 工程化》第七章 权限与安全边界

《Agent Runtime 工程化:生产级 AI Agent 架构、运行时与工程实践》封面

书名:《Agent Runtime 工程化:生产级 AI Agent 架构、运行时与工程实践》

作者:陈堂会

平台:极客日志(https://zeeklog.com)

X:@Megick_com

联系邮箱:[email protected]

章节:第七章 权限与安全边界

第七章 权限与安全边界

能力越大,边界越要清楚。本章谈权限和安全。

Agent 的能力来自工具,风险也来自工具。一个不会调用工具的模型,最多说错话;一个能执行命令、写文件、联网、访问数据库的 Agent,可能造成真实损失。Runtime 的安全目标不是把 Agent 绑住,而是让它在明确边界内做事;越过边界时,停下来请人确认,或者直接拒绝。

安全不是最后加的一层'确认弹窗'。它应该贯穿工具定义、输入校验、执行策略、上下文注入、审计记录和恢复执行。很多事故不是因为系统没有任何防护,而是防护散落在 UI、工具函数和 prompt 里,彼此没有统一语义。

工具权限矩阵

图 7-1:工具风险和权限矩阵。风险来自工具能力、输入参数、资源范围和执行环境的组合,而不是工具名称本身。

7.1 权限系统先回答三件事

设计 Agent Runtime 的权限系统,先回答三件事。

第一,谁要做事?通常是某个 run、某个 step、某个 tool call。权限记录不能只写'Agent 请求执行命令',要有 runId、stepId、toolCallId。

第二,要做什么?包括工具名、参数、资源、预期副作用。run_command("npm install") 和 run_command("ls src") 不能因为工具名相同就被归为一类。

第三,谁批准或拒绝?交互模式下是用户,非交互模式下是 policy engine,企业环境里还可能是组织策略或管理员预授权。

可以定义统一决策对象:

type PermissionDecision = {
  callId: string;
  toolName: string;
  risk: RiskAssessment;
  decision: "allow" | "ask" | "deny";
  reason: string;
  decidedBy: "policy" | "user" | "system";
  expiresAt?: string;
};

type RiskAssessment = {
  level: "read" | "write" | "network" | "install" | "destructive";
  resources: string[];
  sideEffects: string[];
  confidence: "high" | "medium" | "low";
  reasons: string[];
};

confidence 很有用。命令分析器无法确定行为时,应该提高风险等级,而不是乐观放行。

7.2 安全从 workspace 开始

最基本的边界是 workspace。读写文件工具必须把路径解析到工作区内,禁止 ../ 逃逸,谨慎处理符号链接,避免访问用户主目录、SSH key、浏览器 profile、系统 credential 等敏感路径。

路径检查不要只做字符串前缀。应先解析绝对路径,再判断相对关系:

import fs from "node:fs/promises";
import path from "node:path";

async function resolveWorkspacePath(root: string, inputPath: string) {
  const rootReal = await fs.realpath(root);
  const resolved = path.resolve(rootReal, inputPath);
  const relative = path.relative(rootReal, resolved);

  if (relative.startsWith("..") || path.isAbsolute(relative)) {
    throw new Error("Path escapes workspace");
  }

  return resolved;
}

如果工具会跟随符号链接读取真实文件,还要检查 realpath 后的位置是否仍在 workspace 内。对写入工具,则建议默认禁止写入符号链接目标,除非用户明确允许。

workspace 边界还包括忽略目录。.git、node_modules、构建产物、大型缓存、密钥文件、数据库文件,默认不应进入模型上下文。需要访问时,应由工具策略显式允许。

7.3 Shell Policy 要保守、可解释

Shell 是 Agent Runtime 中最危险也最有用的工具。它能快速读项目、跑测试、生成文件,也能删除数据、泄露密钥、安装恶意依赖。

建议把命令分级:

等级示例策略
safe readpwd, ls, rg, cat, sed, wc可自动执行,限制路径和输出
writetouch, mv, cp, apply_patch需要 diff 或 preview
networkcurl, wget, package manager需要域名、方法和用途说明
installnpm install, pip install需要包名、版本、lockfile 说明
destructiverm, git reset --hard, drop table默认拒绝或强确认

命令风险不能只看第一个词。python script.py 可能读文件,也可能删库;node -e 可能只是打印,也可能联网;npm test 通常是测试,但测试脚本可以做任何事。工程上先做保守分类,再逐步扩大自动允许范围。

一个命令分类器可以先返回结构化原因:

type CommandRisk = {
  level: "safe_read" | "write" | "network" | "install" | "destructive";
  reasons: string[];
  requiresApproval: boolean;
};

function classifyCommand(command: string): CommandRisk {
  const text = command.trim();
  const reasons: string[] = [];

  if (/\b(rm|unlink|mkfs|shutdown|reboot)\b/.test(text)) {
    reasons.push("contains destructive command");
    return { level: "destructive", reasons, requiresApproval: true };
  }
  if (/\b(curl|wget|ssh|scp|nc)\b/.test(text)) {
    reasons.push("contains network command");
    return { level: "network", reasons, requiresApproval: true };
  }
  if (/\b(npm|pnpm|yarn|pip|brew)\s+(install|add)\b/.test(text)) {
    reasons.push("installs dependencies");
    return { level: "install", reasons, requiresApproval: true };
  }
  if (/[>|;&]/.test(text)) {
    reasons.push("contains shell operator");
    return { level: "write", reasons, requiresApproval: true };
  }
  if (/^(pwd|ls|find|rg|cat|sed|wc)\b/.test(text)) {
    reasons.push("known read-only command");
    return { level: "safe_read", reasons, requiresApproval: false };
  }

  reasons.push("unknown command");
  return { level: "write", reasons, requiresApproval: true };
}

这不是完美安全沙箱。它是策略入口。真正的执行还应配合工作目录限制、环境变量过滤、超时、输出上限、进程树清理和审计日志。

7.4 Secret Scanning 不只扫文件

工具结果、日志、文件片段进入模型上下文前,应经过 secret scanning。至少检查:

  • API key;
  • OAuth token;
  • 私钥;
  • .env;
  • cloud credential;
  • 数据库连接串;
  • 内部域名和个人信息。

不要只扫描 read_file。rg 搜索结果、测试日志、错误栈、配置打印、命令 stdout/stderr 都可能带出 secret。

发现 secret 后,不要把原文注入模型。可以替换成 [REDACTED_SECRET],并在 trace metadata 中记录'已脱敏'。

type RedactionResult = {
  text: string;
  findings: {
    kind: "api_key" | "private_key" | "token" | "database_url" | "unknown";
    location: string;
    replacement: string;
  }[];
};

如果任务必须处理 secret,比如修改部署配置,应请求用户明确授权,并尽量让处理发生在本地工具中,而不是把 secret 发送给模型。

7.5 供应链风险从安装命令开始

coding agent 很容易倾向'缺包就装'。但安装依赖是供应链入口。Runtime 至少应要求:

  • 展示包名和版本;
  • 识别 package manager;
  • 优先使用 lockfile;
  • 对陌生包提高审批等级;
  • 对 install scripts 保持警惕;
  • 必要时使用 --ignore-scripts;
  • 记录 registry、lockfile diff 和执行环境。

这不是过度谨慎。Agent 自动安装依赖后,项目安全边界就从你的代码扩展到第三方包及其安装脚本。

审批 preview 应该具体:

{
  "toolName": "run_command",
  "command": "pnpm add zod",
  "riskLevel": "install",
  "preview": {
    "packageManager": "pnpm",
    "packages": ["zod"],
    "registry": "default",
    "lockfileMayChange": true,
    "installScripts": "unknown"
  }
}

用户看到这份 preview,才知道自己批准的不是'跑一个命令',而是'改变依赖图'。

7.6 MCP 工具的信任问题

MCP 让工具接入变容易,也让工具信任问题变复杂。一个 Server 暴露的工具描述不应被 runtime 无条件信任。规范中的工具行为注解适合帮助 UI 和模型理解工具,但不应替代本地安全策略。

MCP 工具审批建议按 Server 信任级别分层:

Server 类型默认策略
官方可信、本地只读可自动执行只读工具
团队内部、有审计按工具风险等级审批
第三方远程默认需要确认
未知来源只允许 discovery,调用需显式授权

同时,MCP 的 tools/list 结果进入模型上下文前也要做筛选。不要把几十个不相关工具全部暴露给模型,否则既浪费 token,也增加误调用概率。

MCP Server 断开或工具列表变化时,也应写入 trace。权限系统必须知道'这次调用基于哪个工具列表、哪个 schema、哪个 Server 信任等级'。

7.7 审批记录是系统事实

用户审批不能只当 UI 事件。对 runtime 来说,它是一条系统事实,每次都应写入 audit log:

{
  "runId": "run_123",
  "stepId": "step_7",
  "toolCallId": "call_9",
  "toolName": "run_command",
  "riskLevel": "destructive",
  "preview": "rm -rf build",
  "decision": "denied",
  "actor": "user",
  "timestamp": "2026-08-12T12:00:00+08:00",
  "expiresAt": null
}

恢复执行时,这些记录尤其重要。已经被拒绝的危险工具,不能因为进程重启就再次自动执行。已经批准的一次性操作,也不应无限期复用授权。

审批记录建议分两种:

类型生命周期示例
one-shot approval只对当前 tool call 有效批准一次 apply_patch
scoped approval对限定范围和时间有效本 run 内允许 read_file 读取 src/**

不要默认把用户一次批准扩展成永久授权。授权过宽,会让后续 resume 和自动重试变危险。

7.8 非交互模式必须有 policy

CI、后台任务、定时任务不能等待用户点按钮。非交互模式必须有明确 policy,而不是默认全放行。

示例:

{
  "mode": "non_interactive",
  "workspace": {
    "read": ["src/**", "package.json", "README.md"],
    "write": []
  },
  "tools": {
    "list_files": "auto",
    "read_file": "auto",
    "search_code": "auto",
    "run_command.safe_read": "auto",
    "run_command.write": "deny",
    "run_command.network": "deny",
    "run_command.install": "deny",
    "run_command.destructive": "deny"
  }
}

非交互模式的策略要进入 run metadata。否则同一个任务在本地和 CI 跑出不同结果时,很难解释差异。

7.9 沙箱不是单一开关

沙箱有很多层,不要把它想成一个布尔值。

层级作用
路径白名单控制文件读写范围
命令策略控制 shell 能力
环境变量过滤避免 secret 被子进程读取
网络策略控制外部访问
进程隔离限制不可信代码
容器或 VM隔离文件系统和系统调用
审计日志事后追踪和恢复依据

入门项目可以先实现路径白名单、命令策略和审计日志。生产系统再逐步引入容器、网络隔离、资源配额和组织策略。

关键是不要在 UI 上写'sandbox enabled'就以为安全。你要能说清楚:它隔离了什么,没有隔离什么,失败时怎样处理。

7.10 本章的实现路径

第一步,统一 RiskAssessment 和 PermissionDecision 类型。所有工具调用都先生成风险评估,再执行。

第二步,给文件工具加 workspace 解析、realpath 检查、忽略目录和 secret redaction。

第三步,给 shell 工具加命令分类、工作目录限制、环境变量过滤、超时和输出上限。

第四步,给写入、联网、安装、破坏性操作生成 preview。交互模式询问用户,非交互模式走 policy。

第五步,把所有审批、拒绝、policy 自动裁决写入 audit log,并让 checkpoint 引用这些记录。

第六步,为 MCP Server 增加信任等级和工具暴露筛选。

7.11 验收标准

完成本章后,你应该能解释为什么 Agent 不能直接执行任意 shell;能为 MCP 工具设计权限审批策略;能区分 schema 校验、权限策略和用户确认;能保证恢复执行后不会重复越权。

建议验收用例:

用例期望结果
读取 workspace 外路径拒绝,返回 PERMISSION_DENIED
读取 .env默认拒绝或脱敏后返回
执行 ls src自动允许,限制输出长度
执行 curl https://example.com标记 network,要求确认
执行 npm install left-pad标记 install,展示依赖和 lockfile 风险
执行 git reset --hard默认拒绝或强确认
用户拒绝高风险工具后 resume不自动重放该工具

安全边界做得好,用户才敢把 Agent 放进真实工程目录。它不是'少做事',而是让每一次做事都有依据、边界和后路。


系列文章目录

  • 《Agent Runtime 工程化》完整目录
  • 《Agent Runtime 工程化》第一章 Agent Runtime 全景
  • 《Agent Runtime 工程化》第二章 TypeScript / Node Runtime 基础
  • 《Agent Runtime 工程化》第三章 最小 Agent Loop
  • 《Agent Runtime 工程化》第四章 工具系统设计
  • 《Agent Runtime 工程化》第五章 上下文工程
  • 《Agent Runtime 工程化》第六章 MCP 与 Provider 抽象
  • 《Agent Runtime 工程化》第七章 权限与安全边界
  • 《Agent Runtime 工程化》第八章 Checkpoint、Resume、Rollback
  • 《Agent Runtime 工程化》第九章 可观测与 Trace
  • 《Agent Runtime 工程化》第十章 Eval Harness 与 CI 回归
  • 《Agent Runtime 工程化》第十一章 Agent Runtime 进阶学习路线
  • 《Agent Runtime 工程化》第十二章 hermes-agent 产品级实战
  • 《Agent Runtime 工程化》附录

目录

  1. 第七章 权限与安全边界
  2. 7.1 权限系统先回答三件事
  3. 7.2 安全从 workspace 开始
  4. 7.3 Shell Policy 要保守、可解释
  5. 7.4 Secret Scanning 不只扫文件
  6. 7.5 供应链风险从安装命令开始
  7. 7.6 MCP 工具的信任问题
  8. 7.7 审批记录是系统事实
  9. 7.8 非交互模式必须有 policy
  10. 7.9 沙箱不是单一开关
  11. 7.10 本章的实现路径
  12. 7.11 验收标准
  13. 系列文章目录

更多推荐文章

查看全部
  • OpenClaw 桌面自动化智能体部署与使用教程
  • AI 大模型如何重塑就业生态与产业机遇
  • AI 产品经理晋升路线图:从入门到精通的进阶指南
  • Kali Linux 2025.4 发布:Wayland 默认、桌面与工具链更新
  • 李飞飞解析:世界模型与语言模型的本质区别
  • Rspack:基于 Rust 的高性能 Web 构建工具详解
  • Linux 线程安全与线程同步
  • Android Framework 核心机制解析:Binder、Handler 与系统启动流程
  • voidImageViewer:支持 GIF 与 WebP 的轻量级 Windows 看图工具
  • Spring Boot 自动配置原理深度解析
  • 2026最强外贸工具:Megick
  • MySQL 核心原理与实战指南
  • 2020 年信奥赛 C++ 提高组 CSP-S 初赛真题解析(选择题 11-15)
  • Java 多文件上传
  • 动态规划路径类 DP 入门:最小路径和、迷雾森林与过河卒
  • Java JDK 21 安装与环境配置指南
  • LLaMA-2 与 Mixtral 提示词调优技巧
  • ASKO3-X 全双工语音通信解析:从 WebRTC 到 QUIC 的演进
  • Rust 核心内存安全机制:所有权、借用与生命周期
  • Web 自动化测试入门指南:从概念到 Selenium 实战

相关免费在线工具

  • 编码工具包

    Base32/Base58 编解码、JSON 片段 URL 安全转义等,与 URL/HTML/Base64 工具互补。 在线工具,编码工具包在线工具,online

  • 打乱字符串

    确保字符串 url、文件名和 id 安全。 在线工具,打乱字符串在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online