Part V · Engineering & Governance

15 不做权限系统 把安全边界整个推给操作系统,这个论证站得住吗

已发布 内建沙箱 无 project trust 只管加载 容器化方案 3 种
§1 Mental Model 一句话心智模型

先记住这一句

pi 没有权限系统,而且明确拒绝做一个。它的论证是:部分沙箱最危险的地方不是防不住,而是它看起来像个边界。真正的隔离必须来自操作系统或虚拟化,所以核心一行都不做。

这是全书争议最大的设计决定,也是最容易被简化成「pi 不安全」的一条。要评价它,先得把两件常被混为一谈的东西分开:

把 project trust 当成沙箱,是使用 pi 时最危险的误解。它自己的文档也是这么强调的。

§2 Evidence 代码实证

论证原文

README 的措辞是描述性的:pi 不含用于限制文件系统、进程、网络、凭证访问的内建权限系统,默认以启动它的用户和进程的权限运行。README.md:40

docs/security.md 给出的才是论证本体:

packages/coding-agent/docs/security.md原文 L35
This is intentional. Pi is designed to operate on local source trees, invoke project
toolchains, and integrate with the user's existing development environment. A partial
in-process sandbox would be easy to misunderstand as a security boundary while still
depending on the host shell, filesystem, package managers, credentials, and extension
code. Real isolation needs to come from the operating system or a
virtualization/container boundary.
论证结构:①目标就是要碰宿主工具链 → ②进程内沙箱必然漏(shell、包管理器、扩展代码都在边界外) → ③一个漏的边界比没有边界更糟,因为它会被信任。

紧接着一段把 project trust 的定位钉死:它只是输入加载的守卫,防的是仓库在你批准之前悄悄改 pi 的设置或扩展;它不会让不可信的代码、不可信的 prompt、或不可信的模型输出变得安全。security.md:37

同一段还有一句在同类项目文档里罕见的坦白:来自仓库文件、注释、文档、构建输出的 prompt injection,是本地 agent 的预期风险,pi 无法可靠防止。这不是免责声明的位置——它出现在解释设计的正文里。

project trust 具体管什么

触发条件是一份明确的清单——从当前目录发现以下任一项,就认为该项目「有需要信任才能加载的资源」:security.md:9–16

要信任才加载无论如何都加载
.pi/settings.jsonAGENTS.md
.pi/extensions、skills、prompts、themesAGENTS.override.md
.pi/SYSTEM.md、.pi/APPEND_SYSTEM.mdCLAUDE.md
项目 .agents/skills用户级/全局扩展、CLI -e 扩展

右边这一列值得盯一眼。上下文文件(AGENTS.md / CLAUDE.md)无视 project trust 一律加载。security.md:27 也就是说:clone 一个陌生仓库后启动 pi,即使拒绝信任,那个仓库的 AGENTS.md 也已经进了系统提示。

这在 pi 自己的威胁模型里是自洽的(prompt injection 本就在边界之外),但它把「拒绝信任」这个动作的保护范围压得比多数人直觉中窄得多。

非交互模式没有信任提示

-p、--mode json、--mode rpc 都不弹信任提示。没有已保存决定时,默认值 "ask" 与 "never" 都会忽略这些资源,只有 "always" 才信任。security.md:29

默认拒绝——对自动化场景是正确的方向。

补偿方案:三种容器化模式

方案隔离的是凭证在哪
Gondolin(micro-VM 扩展)内建工具与 ! 命令留在宿主
Docker整个 pi 进程进容器
OpenShell整个 pi 进程 + 策略控制可留在网关外

文档给了一条容易被忽略的提醒:扩展在 pi 进程所在的地方运行。用 Gondolin 把内建工具路由进 VM 时,其它自定义扩展的工具仍在宿主上跑,除非它们也自己做委派。containerization.md:17

还有一条同样实在:bind-mount 宿主工作区为读写时,容器/VM 里的写入照样改宿主文件。security.md:53 容器隔离的是进程,不是你挂进去的那个目录。

安全边界的显式定义

文档最后一段划出了「什么不算漏洞」:预期的本地 agent 行为、没有内建沙箱这件事本身、来自不可信内容的 prompt injection、用户自己装的扩展或 skill 的行为——除非报告能证明存在真正的权限边界绕过,或证明 pi 授予了本地用户原本没有的访问权。security.md:59

把边界写清楚本身是负责任的做法——它让安全研究者知道什么值得报,也让用户知道自己在承担什么。

锚点之后本章逐字引用的 security.md 与 containerization.md 在 25cc5c7(2026-09-22)的文档重写中被重写,引文在新版里大多找不到原句;论点没变:没有内建权限系统,project trust 只管启动时加载什么,security.md:33。新出现的一处值得注意:工具带上了 MCP 风格的 annotations,文档说「权限扩展」可以据此决定哪些调用要确认,extensions.md:167——确认逻辑仍然交给扩展,不在核心里。

§3 Design 设计动机与权衡

这个论证的强项

「部分沙箱会被误当成边界」不是托词,它有真实的历史支撑:进程内的权限提示一旦存在,用户就会形成「pi 会拦住危险操作」的心智模型,而绕过它的路径多到数不清——一条 bash 命令、一个 npm 生命周期脚本、一个扩展、一个语言服务器。要拦住这些,你要重新实现的是操作系统。

而 pi 的目标场景恰恰要求这些能力全开:跑项目的 toolchain、装依赖、执行测试。一个「安全的编码 agent」如果不能跑 npm test,那它没解决用户的问题。

这个论证的弱项

论证成立的前提是二分法:要么有真边界,要么没有。但现实里存在中间物,它们的价值不在于「拦住攻击者」而在于「拦住事故」:

这些不是「被恶意绕过」的场景,是「模型犯错」的场景,而模型犯错是高频事件。针对高频事故的确认提示,与针对攻击者的安全边界,是两个不同的产品;pi 用「不做安全边界」的理由把两者一起否掉了。

公平地说,pi 并非完全没有事故防线——AGENTS.md 里那份 git 禁令清单(第 17 章)正是干这个的,只不过它是写给模型的纪律,不是运行时的拦截。区别在于:纪律靠模型遵守,拦截不靠。

与 Claude Code 的对照

Claude Code 走了另一条路:有权限系统,工具调用按模式询问用户。它同样不是安全边界(一条被批准的 bash 命令可以做任何事),但它把「模型即将做一件不可逆的事」这个时刻暴露给了人。

两者的取舍差异可以概括为:pi 认为不完整的边界会误导用户,因此不提供;Claude Code 认为不完整的边界仍能减少事故,因此提供并说明它不是沙箱。这是产品哲学分歧,不是谁对谁错——但用户需要知道自己选的是哪一种。

值得注意的是,pi 的立场在它自己的目标用户身上更容易成立:一个能配 Gondolin micro-VM 的开发者,确实不需要进程内的假边界。

§4 Limits 边界与失效条件

这个设计在什么条件下失效

检查过并确认的:security.md 的 Security Policy 链接指向旧仓名 pi-mono(漂移 d2,见 漂移记录)。目前靠 GitHub 301 重定向仍可达,但安全策略链接依赖第三方重定向不是好实践。security.md:57

§5 Takeaway 拿走什么
§ Self-check 自测

场景你 clone 了一个陌生仓库,启动 pi,在信任提示里选了「不信任」。这个仓库的 AGENTS.md 会进系统提示吗?

看答案

B。AGENTS.override.md / AGENTS.md / CLAUDE.md 无视 project trust 一律加载(除非整体关闭上下文加载)。project trust 管的是 settings / 扩展 / skills / 主题这类会改变 pi 行为的资源。security.md:27

场景你用 Gondolin 扩展把内建工具全路由进 micro-VM,同时还装了三个自己写的扩展工具。那三个工具在哪跑?

看答案

C。「Extensions run wherever the pi process runs.」Gondolin 覆盖的是 read/write/edit/bash/grep/find/ls 与 ! 命令;其它扩展工具除非自己委派,否则留在宿主。containerization.md:17

基于 earendil-works/pi @ ac4ac9e(2026-08-07 快照)。
仓库 commit 速度约 428/月,行号引用仅对该 SHA 有效。