Memo Code 安全设计:子进程、命令防护与权限审批的统一方案
从 memo 的实践中提炼出安全设计的三道防线:子进程管理防止内存泄漏与资源耗尽、命令守卫拦截危险操作、审批系统平衡权限与体验。还有那把「双刃剑」——dangerous 模式。

做 Agent 这类能「替用户干活」的工具,安全性是躲不掉的坎。
我一开始做 memo(https://github.com/minorcell/memo-code)的时候,安全问题还没想那么多——能跑起来就行。后来工具越加越多,shell 命令也越跑越复杂,就开始踩坑了:
- 子进程忘了关,内存慢慢涨
rm -rf /差点真被我跑出来- 每次执行都要点批准,用户体验稀碎
这些问题逼着我认真设计了整套安全方案。今天把思路和实现细节都分享出来,希望对你有帮助。
先想清楚:安全设计要解决什么问题?
我把它拆成三件事:
- 资源可控:子进程不能无限开,不能忘了关
- 操作安全:危险命令要拦截,误操作要有缓冲
- 权限平衡:该拦的拦住,该放的放行,还要给用户留个「后门」
下面逐一展开。
第一道防线:子进程管理——防止内存泄漏与资源耗尽
memo 的 shell 执行用的是 Node.js 的 child_process.spawn,但光 spawn 是不够的——你还得管得住。
统一会话管理器
我写了一个 UnifiedExecManager(packages/tools/src/tools/exec_runtime.ts),核心思路是单例 + 会话池:
好处很明显:
- 所有子进程都有唯一 ID
- 随时可以查询状态、发送信号、获取输出
- 资源回收有统一入口
资源限制:数量 + 内存 + 时间
先看数量限制:
超过 64 个活跃会话就直接拒绝,防止被LLM恶意耗尽系统资源。
再看输出限制。Agent 交互是基于 token 计费的,子进程输出不能无限制返回:
默认最多返回 8000 字符,不够可以调,但不会无限大。
超时终止:SIGTERM → SIGKILL
子进程跑飞了是常见问题。memo 的策略是先礼貌后强硬:
为什么要等一下?因为有些程序接收到 SIGTERM 会做清理工作(比如写入缓存、关闭句柄),直接 SIGKILL 可能导致数据丢失。
内存泄漏防护:自动清理已退出的会话
会话不能只增不减。我加了一个自动清理逻辑:
这样即使跑了几百个命令,内存也不会无限涨。
第二道防线:命令守卫——拦截危险操作
子进程管住了还不够,还得管住跑什么命令。
我见过太多「rm -rf /」惨案,也见过 dd if=/dev/zero of=/dev/sda 这种物理层面不可逆的破坏。memo 的做法是命令解析 + 黑名单匹配。
命令解析:不只是字符串匹配
直接正则匹配 rm -rf 是有漏洞的。比如 sudo rm -rf /、包裹在 bash -c 里、甚至写成十六进制,都能绕过简单匹配。
memo 的做法是先把命令拆成「段」,再逐段解析:
这样不管外面包了多少层 sudo env bash -c,最终都能追溯到真正的命令。
危险命令黑名单
目前 memo 拦截这几类(packages/tools/src/tools/command_guard.ts):
拦截后返回的是 <system_hint> 标记,不是直接报错,方便 Agent 理解为什么被拦:
第三道防线:审批系统——平衡权限与体验
命令守卫是第一道关卡,但还有很多「不危险但需要知道」的操作,比如写文件、改配置。审批系统的目标就是分级管理、可追溯、可配置。
风险分级
memo 把工具分成三级(packages/tools/src/approval/constants.ts):
审批模式
- auto 模式:只读工具免审批,写/执行类工具需要审批
- strict 模式:所有工具都需要审批,一个都跑不掉
审批记忆:一次批准,记住一整场
如果每次执行都要点批准,用户体验会非常差。memo 用指纹 + 缓存解决这个问题:
- session:这场对话内一直有效
- once:用一次就失效
- deny:以后再问直接拦截
dangerous 模式
审批系统是安全了,但有时候用户就是想要「无限制」——比如在本地开发、或者明确知道自己在干什么。
memo 提供了 dangerous 模式:
开启也很简单,CLI 里加上 --dangerous 标记:
开启后:
- 所有工具都免审批
这是一把双刃剑。 我在 CLI 里加了这个选项,但默认是关闭的。开发者如果想用,需要明确加上 --dangerous 标记。
总结:三层防护 + 一个后门
memo 的安全设计可以总结为:
- 子进程管理:数量限制 + 输出截断 + 超时终止 + 自动清理
- 命令守卫:命令解析 + 黑名单拦截 + stdin 检测
- 审批系统:风险分级 + 审批模式 + 记忆缓存
- dangerous 模式:留一个「我知道我在干什么」的后门
这套方案不完美,还在持续迭代。比如命令守卫目前是硬编码的黑名单,后续可以考虑支持用户自定义规则;审批系统也可以考虑接入外部信任模型。
(完)