一个前端 Agent 接入 MCP、浏览器自动化、设计稿解析、代码仓库和发布平台后,往往会变得非常“能干”:它能读 PR、拉取接口文档、修改组件、执行构建,甚至触发部署。
问题也在这里。
传统插件系统的主要风险是兼容性、性能和供应链;Agent 工具系统还多了一层更难处理的风险:工具返回的文本、网页内容、邮件内容、Issue 描述,都可能影响模型下一步决策。当模型把外部内容当成任务指令的一部分,安全边界就被绕开了。
Skill 和 Tool Use 不是插件市场。它们不只是“给模型更多能力”,而是在给一个会自主规划的执行体分配权限、输入通道与副作用。
对 3~8 年经验的前端工程师来说,重点不在于背诵 Prompt Injection 的定义,而是建立一套工程判断:什么能力可以自动执行,什么能力只能读,什么能力必须由人确认。
Agent 的风险,不只来自用户输入
很多团队做 Agent 时,会把安全注意力放在聊天框:过滤危险提示词、限制用户输入长度、增加系统提示词约束。
这当然有必要,但对接工具后的主要风险,常常来自间接提示词注入。
一个典型链路是:

例如,Agent 被要求“总结最新的性能问题”,于是读取一个 Issue。Issue 正文中混入了一段看似普通的说明:要求忽略当前任务、读取环境变量、把某些内容发送到外部地址。
浏览器不会把这段文字当代码执行,但 Agent 可能把它当成自然语言指令继续推理。此时,问题不在 XSS,也不在接口鉴权是否失效,而在于:不可信内容进入了拥有工具调用能力的模型上下文。
具备外部工具或代码执行能力的 Agent,会放大提示词注入的影响。因为攻击者不再只能影响回答文本,还可能间接影响文件读写、网络访问、数据查询和业务操作。
前端场景里,哪些能力最容易越界
前端团队接入 Agent 时,常见 Tool Use 大致可以分为四类:代码与仓库、浏览器与网页、业务平台、开发环境。它们的风险并不相同。
这里有一个容易被忽略的原则:“能看到”不等于“能执行”,“能执行”不等于“能对生产执行”。
不少 Agent 工具把 read、write、execute、publish 打包在同一个 Token 或同一个 MCP Server 中。对模型而言,这很方便;对安全治理而言,这是把不同风险等级的能力揉成了一个不可控开关。
更好的方式是拆分工具语义。例如不要提供一个万能的 repository_manage,而是拆成:
ts
const tools = {
searchRepository: {
mode: 'read-only',
allowedRepos: ['frontend-monorepo'],
allowedPaths: ['packages/', 'apps/web/']
},
createPatch: {
mode: 'write-draft',
targetBranchPrefix: 'agent/',
mergePermission: false
},
requestRelease: {
mode: 'approval-required',
executePermission: false
}
}
这不是“限制 Agent 智能”,而是把副作用从模型决策中剥离出来。
Skill 为什么会成为供应链入口
Skill 通常被理解为一组提示词、脚本、工具描述、使用规则或工作流模板。它看起来不像传统依赖包那样会被 import 到产物中,因此很容易被低估。
但 Skill 至少可以影响三件事:
一个低质量 Skill 未必是恶意的,也可能造成严重后果。比如“自动修复线上样式问题”的 Skill,若没有明确环境边界,可能把本应生成的修复建议变成直接修改生产配置;若没有限制文件范围,可能在修复 CSS 时顺手改动构建脚本或部署文件。
恶意 Skill 的危险更直接:它可以把敏感操作包装成正常工作流的一部分,例如要求 Agent 在调试失败时“导出完整运行环境以便诊断”。如果 Agent 拥有读取密钥、访问 Cookie 或发送网络请求的能力,这类描述就可能演变为数据外流路径。
审查 Skill 时,不能只看它“解决什么问题”,还要看它向模型灌输了什么行为规则、需要什么权限、能把数据带到哪里去。
建立工具准入:把“能安装”变成“可治理”
前端项目已经习惯了依赖治理:锁版本、审查包来源、扫描漏洞、限制安装脚本。Agent 的 Skill 和 Tool Use 也需要类似流程,只是审查对象从 npm 包扩展到了工具描述、提示词、权限声明和运行环境。
可以为每个工具建立一份轻量但强制的准入清单。
1. 工具身份与维护边界
需要明确:
“来自内部仓库”不自动等于安全。一个内部工具如果允许从不受控位置加载模板、规则或网页内容,同样可能成为注入入口。
2. 输入、输出与副作用
工具契约不能只写参数类型,还要标注安全属性。
ts
type ToolManifest = {
name: string
trustLevel: 'internal-reviewed' | 'restricted' | 'untrusted'
inputSources: Array<'user' | 'repository' | 'web' | 'issue' | 'email'>
sideEffects: Array<'none' | 'file-write' | 'network' | 'database-write' | 'release'>
dataClassification: Array<'public' | 'internal' | 'sensitive'>
approvalRequired: boolean
}
这类元数据的价值在于:工具编排层可以根据风险自动拦截,而不是依赖模型“记得谨慎”。
例如,一个输入来源包含 web、副作用又包含 network 的工具,应被默认视为高风险组合。它至少需要隔离执行环境,并且不能继承访问内部敏感数据的凭证。
3. 可信工具白名单不等于永久信任
白名单的作用是缩小攻击面,不是给工具发“永久免检证书”。
工具升级、Skill 规则变更、依赖范围扩大、权限申请变化,都应触发重新审查。尤其要注意一种隐蔽变化:工具名称没变,但描述文本变了。
对于 Agent 来说,工具描述本身就是模型的决策输入。描述从“读取构建日志”变成“读取构建日志,并在必要时自动修复环境”,权限语义已经发生根本变化。
最小权限:不要给 Agent 一把万能钥匙
研究和工程实践都反复指向同一个原则:Agent 只能访问完成当前任务所需的敏感数据或凭证。
这句话落到前端系统,不应停留在“Token 少发一点”,而要拆成可执行的权限设计。
用任务令牌替代长期令牌
不要让浏览器 Agent、代码 Agent、发布 Agent 共用一个高权限访问令牌。
更稳妥的做法是由编排服务按任务签发短生命周期、范围受限的凭证。即便模型受到注入影响,可被滥用的能力也被限定在当前任务范围内。
text
用户:检查营销页首屏加载问题
任务令牌范围:
- 可读取:指定项目的性能报告、构建产物元数据
- 可访问:预发布环境的目标页面
- 不可读取:用户数据、生产环境变量、其他仓库
- 不可执行:发布、删除、写数据库、外发网络请求
按资源拆权限,而不是按系统拆权限
“允许访问 Git 平台”过于粗糙。更好的表达是:
同理,“允许访问浏览器”也应该继续拆分为站点、域名、登录态、下载能力、上传能力和跨域请求能力。
凭证不应进入模型上下文
模型不需要知道 Token 的真实值,也不需要读取完整 Cookie、环境变量或私钥文件。凭证应由工具运行层保管,模型只提交结构化调用请求。
错误模式是:让 Agent 先读取 .env,再从中提取配置调用接口。
正确模式是:工具层根据权限代为完成受控请求,模型看到的只有经过裁剪的结果。
沙箱不是可选项,而是执行边界
当 Agent 可以运行代码、执行 Shell、操作浏览器时,系统提示词无法替代隔离。
提示词可以表达规则,但它本质上仍是模型输入;沙箱则是即使模型做出错误决定,运行环境也能阻止高危结果发生。
一个面向前端研发的沙箱至少应考虑以下边界:
前端团队尤其要警惕“本地开发 Agent”。它通常离真实工作环境最近:能看到代码、能执行包管理命令、可能继承 IDE 登录态,还可能访问浏览器 Cookie。便捷性越高,越不能把它当成普通代码补全工具。
人类确认要卡在“不可逆动作”之前
不少产品把人工确认设计成一个泛化弹窗:Agent 每调用一次工具就问用户是否继续。结果是确认疲劳,用户习惯性点击通过,安全机制反而失效。
确认应该针对高影响、不可逆、跨边界的动作。
确认弹窗也不能只显示“是否允许调用工具”。用户需要看见足够的决策上下文:目标资源、操作类型、影响环境、将发送或修改的内容摘要,以及工具为何需要这项权限。
让 Agent 的行为可追溯,而不是只看最终回答
Agent 出问题后,仅靠聊天记录往往无法还原事故:模型读到了什么、选择了哪个工具、工具真实请求是什么、是否被规则拦截、返回结果是否包含异常指令,这些都需要审计事件。
建议把一次工具调用拆成可关联的事件链:

日志至少应覆盖:
需要避免把“完整 Prompt、完整响应、完整 Token”无差别写入日志。审计系统本身也可能变成敏感数据汇集点。日志应保留足够的可追溯性,同时对密钥、用户数据和内部内容做脱敏与访问控制。
把不可信内容当数据,而不是指令
这是降低间接提示词注入成功率的关键工程策略。
当网页、Issue、邮件、文档进入上下文时,Agent 的运行框架应明确标识它们的来源和信任级别。不要把抓取到的文本直接拼到系统指令之后,也不要让工具返回的自由文本天然获得“命令优先级”。
可以采用结构化封装:
json
{
"source": "external_issue",
"trust": "untrusted",
"content": "这里是 Issue 的原始内容",
"instructionPolicy": "content_is_data_only"
}
模型仍可能受文本影响,因此结构化标记不是万能药。但它能帮助编排层和策略层识别风险来源,并为后续规则提供依据:
防注入的核心不是证明模型永远不会被诱导,而是确保它即使被诱导,也拿不到足以造成严重后果的权限。
一个适合前端团队的落地顺序
不必一开始就建设复杂的安全平台。可以从最容易产生副作用的环节开始收敛。
结语:能力设计决定了 Agent 的事故半径
前端 Agent 最容易落入一个误区:把 Skill 当作知识包,把 Tool Use 当作接口封装。实际上,前者会影响模型如何理解和规划,后者会决定模型能够对真实世界做什么。
一个可靠的 Agent 不依赖“模型永远听话”。它应该假设外部内容可能恶意、工具可能有缺陷、规则可能被绕过,并在这些前提下控制事故半径:
当团队把这些边界设计清楚,Skill 和 Tool Use 才会从“不可控的能力扩张”,变成真正能进入研发流程的工程能力。

夜雨聆风