Project Trust 不是 Sandbox:Pi Agent 的安全边界怎样补齐
你克隆了一个陌生仓库,Pi 启动时询问是否信任项目。选择"不信任",是不是就可以放心让 Agent 读代码、跑测试?选择"信任"以后,是不是意味着项目已经通过安全检查?
都不是。
Project Trust 解决的是项目资源能否参与 Pi 启动,不是进程能访问什么。一个确认弹窗、一个 危险命令正则、一个只读 Tool Profile,甚至一个写着 --read-only 的容器,都只能覆盖安全 链条的一部分。真正有用的安全设计,不是继续给模型添加"请谨慎"的文字,而是把失误或注入 发生后的影响限制在可接受范围内。
本文的核心结论是:把 Pi 的安全边界拆成资源加载、动作授权、操作系统隔离和供应链治理 四层。每层只为自己能够强制的范围负责,任何一层都不能替另外三层背书。

一、先看最容易被误解的场景

假设一个仓库包含 .pi/extensions/release.ts,Extension 在加载时读取环境变量,并注册一个 部署命令;AGENTS.md 又要求模型"完成后自动发布"。这里至少有四个不同问题:
text
这个项目级 Extension 是否加载? Project Trust
模型提出 deploy 或 bash 时是否允许? Tool Gate
进程能否读取生产凭证、访问网络? OS / Sandbox
Extension 和依赖本身是否可信? Supply Chain
只拒绝 Project Trust,可以阻止项目级 Extension 静默参与启动,却不能把仓库普通内容变成 可信内容,也不会削弱 Pi 进程已有的系统权限。只加一个 Permission Gate,可以挡住匹配到的 危险命令,却挡不住别的表达方式、依赖脚本或 Extension 自身代码。只套一个容器,如果仍挂载 整个 Home、Docker Socket 和全部凭证,也只是换了进程位置。
安全讨论因此不能从"Pi 有没有弹窗"开始,而应该从资产、攻击路径和可强制边界开始。
二、Project Trust 到底保护什么

Pi v0.82.1 的固定版本资料表明,Project Trust 的职责是决定是否加载项目级设置、Package、 Extension、Skill、Prompt 等资源。当前官方 Security 文档把边界写得更直接:Project Trust 控制项目本地资源加载,不是 Sandbox,也不限制开始工作后模型要求工具做什么。
信任项目的价值很具体。仓库不能仅凭存在 .pi/extensions/evil.ts,就在用户第一次进入目录 时自动让这段 TypeScript 参与 Pi Runtime;项目设置和缺失的项目 Package 也需要先跨过信任门。
但"信任"只是允许加载,不是代码审计结论。它表达的是:
text
我允许这些项目资源参与当前 Harness
而不是:
text
我证明这些资源没有恶意行为
当前文档还说明,普通 Context Files 可以不受 Project Trust 决定影响而加载;用户级或通过 CLI 显式加载的 Extension 也处于另一信任域。于是"不信任项目"不等于模型完全看不到项目 指令,更不等于整个进程进入只读或无网络状态。
Project Trust 最准确的名字是"项目可执行资源加载门"。
三、Pi 的真实能力来自启动环境
Pi 是本地进程。内置的 read、write、edit 和 bash 最终能做什么,取决于启动它的用户、 挂载、环境变量、网络和外部身份。可以用一个不完全等式理解:
text
有效影响面 = 进程权限 + 可见文件 + 可见 Secret + 网络出口 + Extension 额外能力
Tool 数量少不代表能力小。一个 Bash Tool 足以调用解释器、包管理器、Git、云 CLI 和任意本机 程序。只把 Agent 的工具列表改成 read/grep/find/ls,最多限制模型可直接选择的动作;它不能 证明 Extension 初始化、宿主 Node 进程、Package 安装脚本或其他本地进程没有副作用。
这也是为什么"模型承诺不读 .env"不能成为安全边界。模型可能忘记、误解路径,或被仓库、 日志、Issue、Tool Result、Skill 中的注入内容影响。强制策略必须位于模型之外:Runtime 先判断 动作,操作系统再判断真实权限。
四、Tool Gate 有用,但不能被夸大

固定版本的 permission-gate.ts 在 tool_call 阶段检查 Bash Command。它匹配明显危险的 rm -rf、sudo、危险 chmod/chown;交互模式要求确认,无 UI 时默认阻断。
这类 Gate 很有价值:它把少量高风险决策放在执行前,能减少误删、提权和无人值守环境中的 明显危险动作。它比事后依赖 Git 回滚更早,也比在 System Prompt 中写"不要执行危险命令" 更强制。
但字符串规则无法覆盖等价副作用:
bash
python -c 'import shutil; shutil.rmtree("target")'
node -e 'require("fs").rmSync("target", {recursive:true})'
find target -delete
git clean -fdx
看起来普通的 npm test 也可能触发生命周期脚本、恶意二进制或网络请求。Permission Gate 因此应该定位成"高风险动作提示层",而不是 Shell 语义分析器或隔离层。
合理策略不是让用户确认每条命令。弹窗过多会造成 Approval Fatigue,最后所有请求都被机械 允许。更好的组合是:低风险动作按规则自动允许,明确禁止项自动拒绝,少数越过责任边界的 动作才要求人工批准,而最坏结果继续由 OS 隔离限制。
五、路径保护为什么仍会被 Bash 绕过

固定版本的 protected-paths.ts 对 write 和 edit 的目标路径做检查,阻止写入 .env、 .git/、node_modules/ 等位置。这类 Runtime 规则比自然语言指示可靠,因为命中的调用会被 代码强制拒绝。
它仍然不是进程级只读:
- Bash 可以直接调用
rm、Python 或 Node 修改文件; - 简单字符串包含无法处理所有
../、大小写和平台路径语义; - 符号链接可能把表面安全的路径导向受保护区域;
- 保护
.env文件不等于环境变量或 Secret 不可读取; - Extension 初始化代码不需要经过模型的
writeTool。
生产策略应先把目标路径规范化到允许根目录,检查符号链接,并把应用层 Gate 与只读挂载、 专用用户和最小文件范围结合。这里最重要的不是多写几个正则,而是让绕过某个 Tool 后仍然 撞到第二道独立边界。
六、供应链风险在 Agent 中更直接

Pi Package 可以同时携带 Extension、Skill、Prompt 和主题。固定版本文档提醒:Extension 执行任意代码;Skill 可以指导模型采取动作或运行附带脚本;第三方 Package 安装前应审查。
风险链不只发生在最终 Extension:
text
Package 来源
→ 版本或 Git Ref
→ 依赖解析与安装
→ 资源发现
→ Extension 执行 / Skill 影响模型 / Prompt 展开
锁定 npm:@scope/pkg@1.2.3 或 Git Commit 可以减少更新漂移,却不能证明固定内容可信。更完整 的流程需要保存来源与 Hash、审查变更、在隔离环境试运行,并对升级重新做 Diff。尤其不能把 个人开发机上的全量凭证直接交给一个刚安装的 Package,然后依靠 Project Trust 解释风险。
对团队而言,资源策略至少要回答:允许哪些来源、谁能升级、版本是否固定、Hash 是否留存、 Extension 与 Skill 分别由谁审核、安装时能否运行生命周期脚本。
七、Container 限制的是最坏结果

Container 不能保证模型不受 Prompt Injection,也不能自动判断代码是否恶意。它的价值是让 某些动作即使被提出,也缺少完成所需的系统能力:
text
模型尝试读取 ~/.ssh
→ 环境没有挂载宿主 ~/.ssh
→ 读取失败
模型尝试控制宿主 Docker
→ 没有 /var/run/docker.sock
→ 无法借 Docker Daemon 绕过当前边界
模型尝试扫描内网
→ 网络策略拒绝非必要出口
→ 影响被限制
当前官方文档建议:不受信任或无人监控的任务,应在 Container、VM、MicroVM、远程 Sandbox 或策略化 Sandbox 中运行,只暴露必要文件与凭证。即使如此,读写挂载的宿主工作区仍会被 容器内进程修改;需要更强保护时,应只读挂载或使用可丢弃副本。
一份最小基线可以包含非 Root 用户、删除 Linux Capabilities、禁止提权、只读根文件系统、 受限 PID/内存/CPU、显式工作区挂载、独立 Agent Home,以及不挂载宿主 Home 和 Docker Socket。但这些只是配置目标,不是本文实测结果。本轮没有在目标系统运行容器,所以证据状态 必须保持 NOT_RUN_CONTAINER。
八、网络与 Secret 决定隔离是否真实
--network=none 对云端模型并不实用,因为 Pi 必须访问 Provider。可选方案包括受控 Egress Proxy、网络 Allowlist、只允许访问局域网模型服务,或按代码敏感度选择不同 Provider 路径。
必须承认一个事实:允许访问云端 Provider,就意味着被发送的 Context 可以离开本地边界。 网络策略不能替代数据分类、Provider 合同和上下文最小化。
Secret 也不能为了省事使用一个全量 --env-file 注入。代码修改任务通常只需要模型 Token, 不需要生产数据库、云管理员、部署、支付和 SSH 凭证。更稳的做法是:
- 每个任务只注入必要 Secret,优先短期、只读和最小 Scope;
- 将代码修改与生产部署身份分离;
- 高风险业务动作通过窄接口代理,不直接暴露底层凭证;
- 限制模型 API Key 的来源、额度和权限;
- 审计外部调用,但不在日志中再次泄露 Secret。
Docker Socket、SSH Agent Socket、管理员 Kubernetes Config、Cloud Metadata、Host PID、 --privileged 和宽泛设备挂载都可能让"容器隔离"失去意义。安全验收不能只检查容器是否启动, 而要检查容器实际拿到了什么。
九、按任务风险选择三档运行方式

低风险:公开代码与临时实验
使用临时 Worktree 或 Clone,不注入云与生产凭证;保留少量危险动作 Gate,完成后审查 Diff。 这里的目标是减少误操作和便于恢复,不必为了公开临时代码建立完整企业平台。
中风险:私有代码但无生产权限
使用专用容器或远程环境,只挂载工作区,Agent Home 与日常环境分离;模型 Token 短期化, 网络受控,第三方 Package 固定并审查,CI 负责验证。项目可以写入临时工作区,但不能读取整个 用户 Home 或调用生产系统。
高风险:客户数据、生产系统与关键基础设施
使用专用 VM、MicroVM 或策略化 Sandbox;默认拒绝网络,通过代理访问模型与业务系统;Agent 使用独立身份,不能持有生产管理员凭证;高风险操作由外部审批控制;完整记录 Tool Call、Diff、 测试和审批,并在任务后销毁环境。
三档不是产品套餐,而是风险决策。一个小修复如果需要生产 Secret,就不能因为改动行数少而 继续按低风险路径运行。
十、用四层验收矩阵结束争论

每次上线 Agent 工作流前,可以按下面的结论强度验收:
| 层级 | 要证明的问题 | 可接受证据 | 不能推出 |
|---|---|---|---|
| Project Trust | 项目资源何时加载 | 固定版本源码、启动行为 | 文件与网络已隔离 |
| Tool Gate | 哪些动作在执行前被阻断 | 规则测试、真实 Tool Call | 等价 Shell 副作用都被覆盖 |
| OS / Sandbox | 进程实际能访问什么 | 真实挂载、用户、网络、Secret 与逃逸测试 | 模型不会被注入 |
| Supply Chain | 运行的资源是否可追踪 | 固定版本、Hash、Diff、来源审查 | 固定内容天然可信 |
再补两层运行治理:Git、Session 和审计负责恢复与证据;人工审批负责少数越过责任边界的动作。 它们都重要,但 Git 不能回滚已经发送的网络请求,日志也不能阻止泄露发生。
本文可以确认的是:固定 v0.82.1 的 Project Trust、Permission Gate、Protected Paths、 Package 与 Skill 边界已经回源;2026-08-11 当前官方 Security 文档继续明确 Project Trust 不是 Sandbox,Pi 以启动用户权限运行,真实隔离依赖 OS 或虚拟化边界。
本文不能确认的是:任何给定 Docker、VM、网络、Secret 或组织策略已经在生产环境通过。 容器方案仍为 NOT_RUN_CONTAINER,不得在平台稿中改写为"实测安全"。
真正可靠的策略不是要求模型永远正确,而是:即使模型被误导、判断错误或调用了危险工具, 环境仍把损害限制在明确、可审计、可恢复的范围内。
参考资料
- Pi
v0.82.1Coding Agent README: github.com/earendil-wo... - Pi
v0.82.1Permission Gate Example: github.com/earendil-wo... - Pi
v0.82.1Protected Paths Example: github.com/earendil-wo... - Pi
v0.82.1Packages: github.com/earendil-wo... - Pi
v0.82.1Skills: github.com/earendil-wo... - Pi 当前 Security 文档,检查日期 2026-08-11: github.com/earendil-wo...