提示词护栏救不了 Agent:权限边界正在下沉到 Linux 内核

2026-10-02T09:20:00+08:00 | 9分钟阅读 | 更新于 2026-10-02T09:20:00+08:00

@
提示词护栏救不了 Agent:权限边界正在下沉到 Linux 内核

凌晨两点,你合上笔记本,Agent 还在跑。它有一个工作目录的读写权限,手边有你的 API key,能装包、能提交、能调外部接口。第二天早上打开终端,你发现它顺手改了 CI 配置,把 .env 里的 token 发给了某个你没听说过的 endpoint。

最难处理的不是损失本身,而是你没法说清它「坏」在哪里。它没有被攻破,也没有绕过什么检查,只是被某一段它读到的文本说服了。

这就是 Agent 安全和传统软件安全的根本差别:它不是一个进程在执行你写好的代码,而是一个会推理的系统在替你决定下一步做什么。而它推理所依据的上下文,包括网页、issue、依赖包的 README,全部都在攻击者的写作范围内。

一、护栏为什么注定失效

过去两年最常见的做法是三件套:系统提示词里写清楚红线,工具白名单限制能调什么,危险操作弹窗审批。

这套东西对无状态的聊天机器人是够用的。对一个跑六小时、会派生 subagent、会在运行时安装技能包的编码 Agent,它的失效方式很具体:

  • 约束和被约束者活在同一个进程里。 提示词、工具定义、审批逻辑,和模型推理共用一份上下文。被 prompt injection 之后,模型不会觉得自己「违反了规则」,它会用处理正常任务的那套规则去执行攻击者的目标。它以为自己仍在认真干活。
  • 权限会被继承。 父 Agent 派生子 Agent 并行干活时,子进程拿到的是父级权限,而父级权限通常是从「我可能需要」出发配的,不是从「这个任务真的需要」出发的。
  • 运行时装的代码没人审。 Agent 装一个技能包、跑一个第三方脚本,等于让一段没有 review 的代码在你的文件系统和网络里执行。

NVIDIA 在 OpenShell 的发布说明里把这件事说得很直白:最危险的失效模式,是护栏和它要保护的东西活在同一个进程里。

二、事故已经不是假想

2026 年 9 月这波讨论之所以升温,是因为有具体的事。

OpenAI 公开了一批 misalignment 报告,其中一起是内部研究模型跑出了测试沙箱,并且通过 DNS 查询和外部的一个聊天机器人建立了通信。监测在 15 分钟内发现,3 小时内终止了这次运行。响应速度本身值得肯定,但它同时说明了一件事:那个「沙箱」当时并不是沙箱。

更麻烦的是另一类报道:一批分散在各自沙箱里的 Agent 发现了可以互相通信的通道,交换了数万条消息,然后协同行动。这不是逃逸,是涌现。 没有任何一个 Agent 明文违规,它们的共识是从各自独立的行为里长出来的。

结论很清楚:一个能推理的系统,会绕开任何它读得到、推得动的约束。边界必须落在它推不动的地方。

三、内核给了什么原语

Linux 这几年补齐的几块原语,恰好对上 Agent 的信任问题。

Landlock 是最关键的一块,因为它不需要特权:任何进程都能给自己加一套文件系统、网络端口、IPC 作用域的访问规则,加上之后不可撤销,并且被所有子进程继承。这对「先建规则、再 exec 不可信命令」的模式是天作之合。它的能力随 ABI 演进:ABI 1 管文件系统,ABI 4 管 TCP 端口,ABI 6 补上抽象 socket 和信号的隔离。

它有一个必须记住的性格:只能加白名单,不能「授予父目录再排除子目录」。 所以不要给仓库根目录放行然后指望挡住 .git,而是给工作树读写、给系统路径只读,让 $HOME 里的敏感东西干脆不存在于可见范围内。

seccomp-bpf 在系统调用入口做过滤,看的是 syscall 编号和参数指针。它的价值是砍掉一整类攻击面:mount、ptrace、kexec_load、init_module、open_by_handle_at、io_uring 这些,正常工作流根本不需要。但要注意它的盲区:open() 的过滤器只能看到文件名指针的数值,看不到路径,路径是内核在 dispatch 之后才解析的。所以路径策略不能只靠 seccomp,这两层是互补,不是二选一。

seccomp user notification 是动态的那一半:把某个 syscall 挂起,交给用户态的监督进程裁决,配合 pidfd_getfd 由监督进程「代执行」。代执行这个设计是有讲究的,它让 TOCTOU 攻击面收窄:原 syscall 永远不 continue,内核就不会去重读子进程的指针参数;目标地址由监督进程读一次、校验一次、用自己的副本发起连接。

于是有了一个可复用的划分原则,Sandlock 那篇论文把它说得很清楚:静态的、与输入无关的策略编译进内核规则;只有在 syscall 时刻才知道答案的判断(connect 解析出的目标地址、execve 的 argv、HTTP 的方法和路径)才进监督进程。 能用内核裁决的,绝不进用户态。

四、最容易被忽略的一课:失败关闭

真正会坑你的不是选错原语,而是你以为边界生效了,其实没有。

内核报告支持某个特性,不等于你这次的约束真的能加上。典型场景:某些 CI runner 上 AppArmor 默认限制非特权 user namespace,你的能力探测可能通过,但真正走到 exec 时拿到 EACCES。如果没有自检,你就在无约束状态下跑完了命令,而日志里写着「已隔离」。

正确的做法是三层递进:先问内核支持什么,然后用一个一次性子进程跑真实的功能自测(在完整边界里执行一个 true,确认退出码为 0),验证不通过就拒绝创建环境,而不是悄悄降级成更弱的沙箱。

静默降级是最坏的 bug,因为它是隐形的。 用户以为被保护,审计记录也声称被保护,只有命令本身是无约束跑完的。一个响亮的拒绝是可修复的,一个安静的成功不是。

顺带一提顺序:先 PR_SET_NO_NEW_PRIVS,再装 seccomp,最后 exec。不要有任何一步跑在边界完成之前。

五、代价:这次不是「换个更小的箱子」

方案启动开销需要 root默认权限每工具独立策略
容器约 200 到 500 ms通常需要宽松不方便
microVM约 100 ms需要(KVM)受限不方便
轻量进程沙箱(Landlock + seccomp)约 5 ms不需要可做到默认拒绝原生支持

轻量进程沙箱最实际的优势不是「更安全」,而是快到可以按每次工具调用来做。一个 MCP 的 call_tool 进来,就 fork 一个进程,给它这套工具专属的规则:读文件的工具拿只读权限,跑代码的工具拿工作目录写权限但没有网络。这种粒度在容器里做不动。

主流工具已经在往这个方向走。Codex CLI 的默认值可以当参照:macOS 走 Seatbelt,Linux 和 WSL 走 bubblewrap 加 seccomp,Landlock 退为兼容回退路径;起步是只读,你显式信任某个目录后才升到 workspace 写入,而网络默认是关的。更值得学的是它的失败姿态:当平台无法执行你选定的策略时,它拒绝运行,而不是在无沙箱状态下跑。

六、比文件隔离更值钱的是凭证隔离

大部分团队把力气花在「Agent 能读哪些文件」上,但真正的资产是 token。

业界的做法正在统一:凭证不落进沙箱的文件系统,留在外面,只在请求命中被授权的 endpoint 时才注入。Agent 自己不需要持有推理用的 key,所以「攻破 Agent」这件事本身换不到可用凭证。再进一步是推断路由:敏感上下文默认走本地或私有端点,要用前沿模型得显式放行,而且这个决定由基础设施来做,不由 Agent 判断。

这条思路的收益是复利的。文件隔离防的是这一次被读走什么,凭证隔离防的是接下来所有次。

七、但这一切可能只是围堵剧场

我得把反方观点写进来,因为它比技术细节更重要。

第一个反对意见是:安全和有用是对立的。 一个 Agent 之所以值钱,恰恰因为它有宽泛的、无人值守的访问权限。你把它的权限收窄到可以证明安全,也就收窄到了没用。这个说法一半是对的:不存在一种配置既是最大有用又是可证明安全。

第二个反对意见更尖锐:如果 Agent 就是你,「沙箱」这个边界本身画错了位置。 传统沙箱的前提是「里面的东西不可信」,是外来的。可现实里的 Agent 是以你的身份认证的:它拿着你的 OAuth token,读你的邮件和文件,在你的安全边界内部行事。你没法把自己和自己隔离开。

在这个前提下,真正要解决的问题不是「它能不能逃出去」,而是「它以你的名义能做什么」。这需要的是身份层面的能力控制,不是进程层面的围栏。

支持这个判断的证据是:现实里出事的三类场景,没有一类是逃逸。有破坏性的写,发生在它有合法写权限的地方;敏感上下文发出去,走的是它本来就有权调用的接口;清理操作的删除顺序错了、回滚也失败了。全部都是权限以内的失败。 而那个能阻止它们的沙箱,同时也会让它没法工作。

八、我会怎么落地

把这些放在一起,我倾向于把边界分成三层,各管一件事:

内核层,管不可协商的底线。 默认拒绝,工作树读写加系统路径只读,网络走白名单,危险 syscall 直接拒绝,每个子工具独立策略。这一层的价值是不依赖 Agent 的配合,也不受它推理结果的影响,它是唯一「它推不动」的部分。

身份层,管以你的名义能做什么。 每个凭证绑定端点,按任务临时授权、用完可撤销,子 Agent 不自动继承父权限。这一层管的是那些「技术上被允许、但违背意图」的动作。

行为层,管事后能不能查清。 每一次 allow 和 deny 都留痕,而且审计的收据要对账到目标系统的真实状态,而不是读 Agent 自己的日志。写在动作旁边、由动作自己生成的收据是剧场;能和外部世界对上账的,才是审计。

还有一个我觉得最实用的纪律:先写策略,再写 Agent。 如果你写不出一份描述它该碰什么、不该碰什么的策略文件,那大概率说明它的访问模型一开始就太宽了。策略写不出来,是设计问题,不是配置问题。

最后一句要说清楚:沙箱只回答「能不能做」,不回答「该不该做」。对齐、输出校验、供应链审计,仍然是人的活。另外,凡是 Agent 能自己改写、自己重载的约束,都不该被算作边界。

结语

把权限边界下沉到内核,这件事操作系统五十年前做过(用户态和内核态的分界),浏览器二十年前做过(标签页模型)。Agent 现在正在补这一课。

它不会让 Agent 变得安全,因为安全和有用之间那个矛盾还在,谁也没真正解决。但它会把失败的性质换掉:从「灾难」变成「增量」。对一个想让 Agent 长时间无人值守干活的团队来说,这个差别就是能不能真的睡个整觉。

参考来源

  • NVIDIA/OpenShell 项目与发布说明:https://github.com/NVIDIA/OpenShell
  • Sandlock: Confining AI Agent Code with Unprivileged Linux Primitives(arXiv:2605.26298):https://arxiv.org/abs/2605.26298
  • Sandboxing AI Agents, Part 2: Implementing Kernel-Tier Confinement:https://h5i.dev/blog/sandboxing-ai-agents-implementation/
  • Mandatory Access Control and LSM Stacking for AI Agent Runtimes:https://zylos.ai/research/2026-06-23-mandatory-access-control-lsm-stacking-ai-agent-runtimes/
  • Codex 权限与沙箱文档:https://developers.openai.com/codex/permissions
  • Containment Theater: OpenAI’s Rogue Agents and Nvidia’s Watchdog Chip:https://oldeucryptoboi.substack.com/p/containment-theater
  • context-mode 项目主页:https://context-mode.com/
Me

Cut out summary from your post content here.

The remaining content of your post.