当 Agent 开始运行数小时、修改仓库、调用支付与邮件服务,失败后从头再来既昂贵又不现实。检查点与回滚因此成为持久 Agent 的基础能力。但一项针对现有 Agent 框架的安全研究指出:恢复的每一份数据都正确,不代表恢复后的执行仍然安全。
危险来自恢复边界不一致。框架状态、工作区、运行时进程、远程服务与已经发生的外部副作用,往往不会被同一个检查点原子保存。回滚后,它们可能被重新组合成一个从未在正常历史中共同存在过的状态。
#三种检查点,各自漏掉不同世界
框架状态检查点保存消息、工作流节点、中间结果与待执行步骤,但通常不恢复工作区和运行时。LangGraph、CrewAI 属于这一类。
工作区检查点常用影子 Git 保存项目文件。Hermes 与 Cline 能恢复代码和部分任务历史,却通常不覆盖进程、系统环境、项目外文件与远程服务。Cline 甚至允许只恢复工作区、只恢复任务历史或同时恢复,两部分因此可能停在不同时间点。
OS 或虚拟机快照覆盖更广,但仍无法自动回滚支付平台、邮箱、云资源等外部世界。恢复边界再大,也不等于包含 Agent 判断所依赖的全部事实。
研究把安全要求称为“执行连续性”:跨恢复携带的状态、判断、假设和副作用,必须仍能被同一条有效历史共同解释。
#五类基础失效
论文从通用执行模型中归纳出五类问题。
第一,内部状态覆盖不完整。检查点保留了部分组件,却漏掉另一部分依赖。第二,检查点内部不一致,例如工作区与对话历史来自不同时间。第三,外部状态错配:内部仍认为资源绑定未变,远程会话实际已经指向另一个对象。
第四,非确定性重放没有绑定。重新调用模型或工具可能走出不同分支,却继续复用旧判断。第五,外部副作用没有被记录:支付、消息或资源创建已经提交,Agent 在写入完成状态前失败,恢复后便会再执行一次。
这些问题不是简单调整“先保存还是先执行”就能消除。先执行外部动作再提交检查点,故障窗口会丢掉已经发生的副作用;先把状态标记为完成再执行,故障又可能留下“记录完成、实际未发生”的相反错误。
#三个端到端攻击
Hermes 案例中,Agent 先清除仓库恶意代码并完成扫描。回滚把工作区恢复到清理前的恶意版本,却保留了针对干净版本产生的验证结果。恢复后的 Agent 于是把恶意仓库当作已验证版本发布。检查点和扫描都没被伪造,只是验证结果被重新绑定到它从未检查过的文件。
Cline 案例模拟邮箱迁移。检查点记录了对测试邮箱执行转发的待办状态;随后外部邮箱服务把当前会话切到真实邮箱。只回滚任务历史不会恢复远程会话绑定,重放后,原本只获准用于测试邮箱的操作被执行在真实邮箱上,形成未授权转发。
LangGraph 案例模拟付款。用户批准一次付款,节点先提交交易,再向受攻击的远程服务取回回执。回执请求失败,使节点没有完成、付款结果也未进入新检查点;外部交易却已经生效。恢复到“已批准、未付款”状态后,节点再次付款,一次批准产生两次扣款。
#这些不是孤立实现错误
研究团队在 LangGraph、CrewAI、Hermes、Cline 和 E2B 上分析 347 条 TerminalBench 与 AgentBench 轨迹,共形成 1,735 次框架—任务执行。不同框架的失效分布不同,但五类问题在异构恢复设计中反复出现。
框架检查点更容易遗漏工作区;工作区检查点更容易让文件与任务历史不一致;几乎所有方案都缺少对任意外部副作用的原子协调。论文还构造 96 个持久外部动作微基准:执行后提交检查点的顺序失败 90 次,提交后执行失败 93 次。单纯调换顺序不能封闭故障窗口。
#安全恢复需要重新验证依赖
恢复后不能默认沿用旧结论。与安全相关的判断必须绑定到具体对象版本、资源标识与输入摘要:扫描结果绑定文件树哈希,授权绑定目标账户和操作参数,支付绑定稳定幂等键,远程会话绑定重新确认。
对外部副作用,应优先使用幂等 API、事务、补偿操作和可查询的操作标识。恢复器需要先与外部世界对账,再决定重试、跳过或人工介入,而不是把“检查点里没写完成”解释成“外部一定没发生”。
检查点还需要记录恢复边界和未覆盖依赖。用户点击回滚时,系统应该明确哪些组件会恢复、哪些外部状态不会恢复,以及哪些旧判断将被作废。对于高风险节点,恢复后重新授权通常比自动继续更安全。
论文研究的是回滚引入的安全断裂,并不声称五类模式覆盖 Agent 的所有漏洞;攻击能否成立也取决于应用权限和威胁模型。但它揭示了一个基础事实:检查点不是时间机器。它只能恢复被保存的状态,无法自动恢复让这些状态成立的因果关系。