Rust Agent 子进程执行Command 之前先定义输入和超时一、让 Agent 执行命令是高风险能力系统级 Agent 工具常需要调用本地命令比如读取 Git 状态、运行测试、格式化代码。Rust 的std::process::Command很方便但让模型间接执行命令风险很高。输入、路径、环境变量和超时都必须受控。命令执行设计的第一原则是只允许明确授权的动作。不要把模型输出的字符串直接丢给 shell。能不用 shell 就不用 shell参数分开传路径先规范化。上个月我在测试 Agent 的自动修复能力时差点出了事故。Agent 知道可以运行rm命令模型在一次对话中尝试了rm -rf /tmp/xxx。虽然 /tmp 不是核心数据但让我出了一身冷汗。如果一个 Agent 能执行任意命令而开发者没有设白名单那它就是提权工具。从那一刻起我把命令白名单放到了系统设计的最高优先级。二、执行链路要有安全闸flowchart TD A[模型请求执行] -- B[命令白名单] B -- C[参数校验] C -- D[工作目录限制] D -- E[超时控制] E -- F[执行并捕获输出]白名单决定能执行什么参数校验决定怎么执行目录限制决定在哪执行超时控制决定最多等多久。四层少一层风险都会上升。输出也要限制。某些命令会输出大量日志直接塞回模型上下文会浪费 token甚至泄露敏感信息。执行器应截断输出并保留完整日志路径供人工查看。三、Rust 代码要避免 shell 注入use std::process::Command; use std::time::Duration; fn run_git_status(repo: str) - std::io::ResultString { let output Command::new(git) .arg(-C) .arg(repo) .arg(status) .arg(--short) .output()?; Ok(String::from_utf8_lossy(output.stdout).to_string()) }这里没有把整段命令拼成字符串也没有调用 shell。参数逐个传入能减少注入风险。真实项目还要校验 repo 是否在允许目录内。fn is_allowed_command(cmd: str) - bool { matches!(cmd, git_status | cargo_test | fmt_check) }白名单应使用业务动作名而不是原始命令字符串。这样模型申请的是查看状态执行器决定具体命令。生产环境实战经验白名单用业务动作名还有一个好处参数可以校验。git_status动作传给你的参数只有repo你可以在执行器里做路径安全校验。但如果是run_shell: { cmd: git status }你就很难约束参数了。有一次我偷懒用了后一种方式模型在一次测试中传了cmd: git push --force虽然是测试环境没出问题但暴露了安全漏洞。业务动作名虽然写起来多一点但安全边界清楚很多。四、超时和取消不能缺席标准库的 Command 没有直接 timeout需要结合子进程管理或使用 async runtime。长时间运行的测试、卡住的脚本、等待输入的命令都可能让 Agent 挂死。执行器还要处理退出码。非 0 不一定是系统错误测试失败、格式检查失败都是可理解结果。要把退出码、stdout、stderr 和截断状态结构化返回。环境变量也要收紧。默认继承父进程环境很方便但可能把密钥传给子进程。执行命令时可以构造最小环境只传 PATH 或必要变量。涉及 AI 工具时API Key 更不能无脑透传给任意命令。工作目录要做 canonicalize并确认仍在允许根目录内。简单字符串前缀判断可能被..、软链接和大小写差异绕过。路径安全是系统级 Agent 的底线。一个路径越界的真实案例我见过一个 Agent 工具用字符串前缀做路径检查。用户传入path/workspace/../../../etc/passwd前缀判断通过了因为../../..被当成了路径的一部分。工具最终读取了/etc/passwd。后来改成canonicalize之后再检查前缀才堵上这个漏洞。软链接也可能绕过检查所以canonicalize不是可选的是必须的。还要处理 stdin。很多命令等待输入会卡住执行器应默认关闭 stdin除非命令能力明确需要交互。Agent 工具更适合非交互命令交互式任务应转成明确参数。最后审计日志要记录动作名、参数摘要、工作目录、退出码和耗时。命令执行出了问题必须能回放当时发生了什么。五、总结Rust Agent 子进程执行要有命令白名单、参数校验、工作目录限制、超时和输出截断。不要把模型字符串直接交给 shell。Command 很强也很危险。让 Agent 会执行命令之前先让执行器会拒绝命令。