Claude Code/Codex 安全 Agent Harness 实战:权限、验证与回滚
用权限策略、执行计划、验证脚本和回滚日志,为 Claude Code 与 Codex 搭建更安全的 AI Agent 工作流。
Agent 越强,外部约束越重要
刚开始使用 Claude Code 或 Codex 时,很多人会把重点放在提示词上。小修小改时,这确实有效。但一旦你开始让 Agent 处理部署、SaaS API、文件编辑、文章发布、邮件发送,问题就不再只是提示词了。
真正重要的是 Agent 外面的足场,也就是 Agent Harness。
本文把 Agent Harness 定义为:让 AI Agent 安全工作的外部结构,包括权限规则、执行计划、验证脚本、运行日志和回滚路径。Agent 仍然负责理解任务、生成代码和提出改动,但它不能无条件执行所有命令。
如果想先理解概念,可以从 harness engineering 指南 开始。想看具体事故,可以阅读 Claude Code 安全失败案例。如果需要长期上下文管理,也可以结合 Claude Code 与 Obsidian 集成。
这个思路适用于 Claude Code,也适用于 Codex。工具不同,安全结构是相同的。
User request
|
v
Agent
|
v
[1] Policy layer 哪些可以执行,哪些要询问,哪些必须禁止
[2] Plan layer 先做什么,后做什么
[3] Verification layer 如何确认真的成功
[4] Recovery layer 失败后如何恢复
|
v
Files / shell / SaaS APIs / deploy
Claude Code 官方文档中也把 settings、permissions、hooks、MCP 等能力拆开说明。可以参考 Claude Code settings、Hooks reference 和 MCP 文档。
实例1:内容发布 Agent Harness
“发布一篇文章”听起来像一个动作,但实际上是一条工作流。
1. 读取最近7天的访问数据
2. 从高流量主题周边选择新题目
3. 检查是否和旧文章重复
4. 写日文或英文源稿
5. 生成所有语言版本
6. 检查 frontmatter、slug、内部链接
7. 构建网站
8. 检查公开 URL
9. commit 并 push
如果这些步骤只存在于人的记忆中,Agent 很容易只完成“看得见”的部分,比如写正文,却忘记翻译、构建或线上确认。Plan layer 的价值,就是把这些步骤变成固定流程。
实例2:SaaS 连接 Agent Harness
SaaS 连接更需要边界。比如让 Agent 搜集公司信息、生成样例网站、起草销售邮件。
1. 读取公开网页
2. 保存公司名、网站和邮箱
3. 生成样例 landing page
4. 起草邮件
5. 发送邮件
前四步可以自动化,第五步必须要人确认。因为邮件一旦发出,就会影响真实的人,不能简单撤回。
| 操作 | 是否自动 | 原因 |
|---|---|---|
| 读取公开网页 | 可以 | 风险较低 |
| 保存本地CSV | 可以 | 可审查 |
| 生成样例页面 | 可以 | 发布前可检查 |
| 起草邮件 | 可以 | 尚未发送 |
| 发送邮件 | 需要确认 | 外部影响,难以撤回 |
这就是 Agent Harness 的核心:读取、生成、发布、发送要分开。
Policy layer:从 allow、ask、deny 开始
最小的策略文件可以这样写。
{
"allowCommands": [
"npm run build",
"npm run test",
"node scripts/analytics-report.mjs",
"node scripts/content-trend-report.mjs"
],
"askCommands": [
"git push",
"wrangler pages deploy",
"node scripts/outreach-send-mails.mjs --send"
],
"denyCommands": [
"rm -rf",
"git reset --hard",
"curl * | sh",
"npm publish"
],
"protectedPaths": [
".env",
".env.local",
"claudecode-lab-sheets-f54fc47c68f0.json"
]
}
Claude Code 项目设置也可以表达类似边界。
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run build)",
"Bash(npm run test *)",
"Bash(node scripts/content-trend-report.mjs *)"
],
"ask": [
"Bash(git push *)",
"Bash(wrangler pages deploy *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git reset --hard *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./claudecode-lab-sheets-f54fc47c68f0.json)"
]
}
}
不要只写“请小心处理密钥”。应该把秘密文件、破坏性命令、生产部署、外部发送操作写成明确规则。
Verification layer:把成功条件写成脚本
“仔细检查”不是验证。更好的做法是把成功条件变成命令。
// scripts/verify-published-page.mjs
const url = process.argv[2];
if (!url) {
throw new Error("Usage: node scripts/verify-published-page.mjs <url>");
}
const response = await fetch(url, { redirect: "follow" });
if (!response.ok) {
throw new Error(`Page returned ${response.status}: ${url}`);
}
const html = await response.text();
const checks = [
["title", /<title>.+<\/title>/i],
["description", /<meta name="description"/i],
["adsense", /ca-pub-2125588229998303/i],
["analytics", /G-3YR0LE68MJ/i]
];
for (const [name, pattern] of checks) {
if (!pattern.test(html)) {
throw new Error(`Missing ${name} on ${url}`);
}
}
console.log(`OK: ${url}`);
如果文章包含代码块,还应该用 Playwright 检查手机宽度下是否横向溢出。
import { chromium } from "playwright";
const url = process.argv[2];
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 390, height: 844 } });
await page.goto(url, { waitUntil: "networkidle" });
const overflowing = await page.evaluate(() => {
return [...document.querySelectorAll("pre, code, table")]
.filter((el) => el.scrollWidth > el.clientWidth + 4)
.map((el) => el.textContent?.slice(0, 80));
});
await browser.close();
if (overflowing.length > 0) {
console.error(JSON.stringify(overflowing, null, 2));
process.exit(1);
}
Recovery layer:先记录,再回滚
自动化真正危险的地方不是失败,而是失败后不知道改了什么。每次运行都应该留下日志。
{
"runId": "2026-05-19-article-001",
"topic": "agent harness security",
"changedFiles": [
"site/src/content/blog/claude-code-codex-agent-harness-security.mdx",
"site/src/content/blog-zh/claude-code-codex-agent-harness-security.mdx"
],
"commands": [
"node scripts/content-trend-report.mjs --days 7",
"npm run build",
"wrangler pages deploy dist --project-name claudecode-lab"
],
"status": "deployed"
}
Git 工作流中,优先使用有目标的恢复,而不是粗暴 reset。
git status --short
git diff -- site/src/content/blog/target-article.mdx
git revert <bad-commit>
不要让 Agent 随便执行 git reset --hard,尤其是在工作区可能有他人改动时。
最小 Node.js 命令 Harness
下面是一个很小的命令分类器。
const policy = {
allow: [
/^node scripts\/content-trend-report\.mjs( .*)?$/,
/^npm run build$/,
/^npm run test$/
],
ask: [
/^git push( .*)?$/,
/^wrangler pages deploy( .*)?$/
],
deny: [
/rm -rf/,
/git reset --hard/,
/curl .* \| sh/,
/npm publish/
]
};
export function classifyCommand(command) {
if (policy.deny.some((rule) => rule.test(command))) return "deny";
if (policy.allow.some((rule) => rule.test(command))) return "allow";
if (policy.ask.some((rule) => rule.test(command))) return "ask";
return "ask";
}
这个代码很普通,但这正是优点。好的 harness 应该稳定、可预测、容易审查。
团队落地清单:先从出口倒推
初学者最容易犯的 mistake,是一开始就想把 Claude Code 或 Codex 变成“全自动员工”。更稳的方式是先定义每个 workflow 的出口。内容发布的出口不是“文章写完”,而是“公开 URL 返回 200、广告和 Analytics 标签还在、手机端代码块没有撑破页面”。销售自动化的出口也不是“邮件已经发出”,而是“候选公司、样例页面、邮件草稿都能被人工复核”。
把出口写清楚以后,Agent Harness 要做的事情就会变少。
| use case | 可以先自动化 | 必须保留人工确认 |
|---|---|---|
| 内容运营 | 选题、草稿、翻译、内部链接、build | deploy、git push、广告脚本修改 |
| SaaS 集成 | 只读查询、CSV 整理、文案生成 | 邮件发送、删除数据、改计费设置 |
| 安全修复 | 生成 patch、运行测试、写影响范围 | 读取 secret、本番发布、权限放宽 |
真正的 pitfall 是“读取”和“执行”混在一起。Agent 读取网页、issue、日志,本身风险不大;但如果它同时拥有发送邮件、删除数据、部署生产环境的权限,一个被污染的外部文本就可能变成真实操作。OWASP 的 Top 10 for LLM Applications 把 Prompt Injection 和 Excessive Agency 作为重要风险,这和代码 Agent 的日常运维非常接近。
在 Claude Code 侧,可以先阅读官方 security guide 和 permissions guide。在 Codex 侧,OpenAI 的 code generation guide 适合作为定位参考。团队内部则建议把 Claude Code 安全失败案例 和 危险 prompt 对策 作为入门材料。
如果你只是想快速复制可用模板,可以从 /products/ 下载检查清单和设置样板。如果要把权限、CI、部署、审核流程一起设计,/training/ 更适合,因为 harness 的价值通常出现在“已经开始把真实业务交给 Agent”的阶段。
评审时只看六个问题
团队评审 Agent Harness 时,不需要把所有提示词逐字讨论。更有效的是固定六个问题。第一,Agent 是否能读取 secret。第二,是否有外部副作用,例如发送、删除、部署、收费。第三,失败后能否知道改了哪些文件。第四,成功条件是否能用命令验证。第五,是否有移动端或多语言这类容易被忽略的检查。第六,是否有一个人类可以理解的日志。
这个 review 列表很朴素,但它能让非安全背景的成员也参与。产品负责人可以判断哪些动作必须审批,工程师可以判断哪些命令应该 deny,运营人员可以判断哪些结果需要人工确认。Agent Harness 的目标不是让流程复杂,而是让风险被看见。
如果一个 use case 连这六个问题都回答不清楚,就不要先接生产环境。先让 Agent 只生成计划、差分和报告。等 workflow 连续多次通过验证,再把少量低风险命令放进 allow。这样做虽然慢一点,但比一次性给 Agent 太多权限更容易长期运营。
还有一个小技巧:把“自动”和“手动”写成状态,而不是口头约定。例如 drafted、reviewed、approved、sent 四个状态,比“确认一下再发”更可靠。Agent 只能把任务推进到 reviewed,人类确认后才进入 approved,发送脚本只接受 approved 的记录。这个状态机很简单,却能防止很多误发送和误部署。
总结
AI Agent 的质量不只取决于提示词。真正进入实务后,质量来自模型外面的结构。
- Policy:什么可以做,什么必须问,什么禁止
- Plan:执行前先明确步骤
- Verification:用命令证明成功
- Recovery:失败后知道如何恢复
当你让 Claude Code 或 Codex 接手更多工作时,不要只加长提示词。先搭建 Agent Harness。这样才能从“能修改文件的 AI”走向“可以安全承担一部分业务流程的 AI”。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code Permission Receipt Pattern:记录权限、证据和回滚方式
Claude Code 权限 receipt:记录允许动作、需要批准的边界、验证命令、回滚说明,以及 Gumroad 和咨询 CTA 检查。
Claude Code 子代理实战指南:安全委派并行文章与代码工作
用 Claude Code 子代理安全拆分文章和代码工作:委派规则、提示词模板、失败模式与检查清单。
Claude Agent SDK 入门:把 Claude Code 安全嵌入应用
用最新 Claude Agent SDK 构建可审计的 AI 代理,涵盖权限、MCP、代码示例和坑点。