AI 编程 Agent 权限闯祸不是段子,我从 Claude Code 源码里扒了一套安全防线方案
AI 编程 Agent 权限闯祸不是段子,我从 Claude Code 源码里扒了一套安全防线方案
导语
你让 AI Agent 帮忙整理项目文件,结果它「顺手」把你几个文件夹删了——因为你没说不能删。你让它写个爬虫脚本,它把线程开到 200,直接把对方服务器打崩了——因为你只说了「快点抓」。你让它跑个数据库迁移,它直接连上了生产库——因为你没说是本地环境。这些不是段子。2026 年,AI 编程 Agent 从「对话工具」进化成了「自主执行体」,能操作文件、跑命令、调 API——能力越大,失控的破坏力也越大。Cloudflare 的 AI 安全报告显示,62% 部署了 AI Agent 的企业遇到过权限失控导致的安全事件。今天我就扒一扒 Claude Code、Amazon Q CLI 这些工业级 Agent 是怎么做安全防线的,以及我们自己的项目可以怎么抄作业。
从脑补到动手:AI Agent 发生了什么?
先搞清楚一件事:AI Coding Agent 和聊天机器人本质不同。
聊天机器人只负责「说」,AI Agent 直接「做」。当你让 Claude Code「修一下 src/app.js 里的 bug」时,背后的链路是这样的:
你 → LLM 思考「先看看文件」→ 输出工具调用 fs_read("src/app.js")
→ Agent 执行读取 → 结果返回 LLM → LLM 思考「找到 bug 了」
→ 输出工具调用 fs_write("src/app.js") → Agent 执行修改 → 返回结果
→ LLM:「搞定了,第 42 行那个变量拼写错误」
这个过程叫 Agent Loop(智能体循环)。关键点在于:LLM 不直接操作你的电脑。它通过结构化的 JSON 告诉 Agent「我想做什么」,Agent 经过权限校验后代为执行。所有操作都可审计、可拦截、可回滚。
这个设计本身就是第一道防线——但它不够。
Anthropic 内部维护的 Agent 不当行为事件日志里,真实的翻车案例包括:
- Agent 误解指令直接删除了远程 Git 分支
- 把工程师的 GitHub 认证令牌上传到内部计算集群
- 尝试对生产数据库执行迁移脚本
- 把爬虫并发数开到 200 线程打崩目标服务器
这些问题的根源只有一个:Agent 权限管控没做到位。
Claude Code 的六层权限模型,比你想的复杂得多
我翻了一遍 Claude Code 的源码,它的权限模型不是简单的「允许/拒绝」二级开关,而是六层渐进式防护:
用户输入
↓
① Deny Rules(硬拒绝规则)—— 明确禁止的操作,直接拦截不询问
↓
② Ask Rules(询问规则)—— 哪些操作需要弹窗确认
↓
③ 工具自检(Tool Self-Check)—— 工具自身的只读/写入属性判定
↓
④ Permission Mode(权限模式)—— 根据当前模式调整放行策略
↓
⑤ 白名单(Allow List)—— 已信任的操作自动放行
↓
⑥ 用户确认 / Classifier 并发竞速 —— 弹窗 or AI 分类器自动判定
每一层都承担不同的职责,组合在一起就形成了一个纵深防御体系。
第一层:Deny Rules —— 先说清楚「绝对不能做」
Deny Rules 是最硬的底线。在 Claude Code 里,项目级别的 deny rules 定义在 .claude/settings.json 中:
{
"permissions": {
"deny_rules": [
{
"tool": "Shell",
"glob": "rm -rf /",
"reason": "禁止删除根目录"
},
{
"tool": "Shell",
"glob": "git push --force",
"reason": "禁止强制推送"
},
{
"tool": "FileWrite",
"glob": "**/node_modules/**",
"reason": "禁止修改 node_modules"
}
]
}
}
这些规则会被缓存到内存里,每次工具调用前先做一次快速匹配。命中的操作根本不会送到 LLM 那边讨论——直接拒绝,连弹窗都没有。
第二层:Ask Rules —— 需要你点头的事
有些操作不致命但需要你确认。比如写文件、执行非白名单命令、访问敏感路径。Ask Rules 定义了哪些操作需要用户手动批准:
{
"permissions": {
"ask_rules": [
{
"tool": "Shell",
"glob": "npm publish",
"reason": "发布 npm 包需要确认"
},
{
"tool": "FileWrite",
"glob": "**/*.env*",
"reason": "修改环境变量文件需要确认"
}
]
}
}
第三层:工具自检 —— 内置的只读/写入判别
每个工具在注册时都声明了自己的安全属性。比如 fs_read 标记为 isReadOnly: true,不需要权限检查;fs_write 标记为 isReadOnly: false,必须走权限流程。
// Claude Code 源码权限模型简化示意
interface ToolPermission {
toolName: string
isReadOnly: boolean
allowedArgs?: string[]
deniedArgs?: string[]
}
const tools: ToolPermission[] = [
{ toolName: 'Read', isReadOnly: true },
{ toolName: 'Write', isReadOnly: false },
{ toolName: 'Edit', isReadOnly: false },
{
toolName: 'Shell',
isReadOnly: false,
deniedArgs: ['rm -rf', 'sudo', '> /dev/sda']
}
]
这个设计思路很值得学习:在框架层面就让工具自身知道自己的权限边界,而不是靠外部规则覆盖一切。
第四层:Permission Mode —— 三种模式应对不同场景
Claude Code 为不同信任场景设计了三种权限模式:
| 模式 | 用途 | 安全等级 |
|---|---|---|
| Plan Mode | 只读分析,不能执行任何写入操作 | 🔒 最高 |
| Auto Mode | 自动模式,AI 分类器可选地批准部分操作 | 🟡 中 |
| Full Mode(默认) | 每次写入操作都要用户确认 | ✅ 安全 |
| Dangerously-Skip | 跳过所有权限检查(不推荐) | ❌ 危险 |
其中 Auto Mode 是 Claude Code 2026 年的亮点设计。它内置了一个安全分类器,能拦截 95% 以上的明显危险操作,同时减少用户的「审批疲劳」。Anthropic 自己的数据显示,用户平均批准了 93% 的权限提示——既然大部分都会被批准,不如让 AI 自己判断什么时候需要问人。
第五层:白名单 —— 信任是一点点建立的
在项目首次启动时,Claude Code 会检测项目结构化信息(package.json,是否存在 .git,项目框架类型等),判断项目的「信任级别」。信任级别高的项目,部分操作可以免审。
第六层:最终兜底 —— 用户确认弹窗
当所有自动化检查都通过不了,最终交到用户手里。弹窗内容包括:操作类型、目标文件/命令、安全风险等级。用户有三个选项:允许一次、永远允许、拒绝并阻止后续类似操作。
Amazon Q CLI 的状态机方案,另一种思路
和 Claude Code 不同,Amazon 的 Q Developer CLI 用 有限状态机 来管理 Agent 的安全:
// Amazon Q CLI 安全状态机(简化 Rust 伪代码)
enum AgentState {
Idle,
ExecutingRequest,
ExecutingHooks, // 执行前置安全钩子
WaitingForApproval, // 等待用户审批
ExecutingTool, // 工具执行中
ToolResultProcessing, // 处理工具结果
}
这个状态机的关键设计在于 ExecutingHooks 状态——每次工具调用前,先执行一组安全钩子。钩子可以是:
1. 权限检查钩子:检查当前操作是否在白名单中
2. 速率限制钩子:防止 Agent 短时间内执行大量破坏性操作
3. 依赖分析钩子:检查要修改的文件是否被其他模块依赖
4. 资源限制钩子:限制并发数、内存使用等
这种方式的好处是安全逻辑和 Agent 逻辑完全解耦,你可以像插拔插件一样增删安全策略。
我们自己怎么落地?
光看别人家的设计不过瘾,我给一个自己项目里能直接用的方案。核心就三个字:中间层。
在你的 AI Agent 和实际执行环境之间,加一层安全代理。以下是一个最小可用实现:
# agent_guard.py — AI Agent 安全代理,放你自己项目里就能跑
import re
import json
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class DenyRule:
pattern: str
reason: str
action: str = "deny" # deny | ask | log
class AgentGuard:
def __init__(self):
self.deny_rules: List[DenyRule] = []
self.rate_limiter = {} # 简单速率限制
self.audit_log = []
self._load_default_rules()
def _load_default_rules(self):
"""加载默认安全规则"""
self.deny_rules = [
DenyRule(r"rms+-rfs+/", "禁止删除根目录"),
DenyRule(r"gits+pushs+--force", "禁止强制推送"),
DenyRule(r"DROPs+TABLE", "禁止删除数据库表"),
DenyRule(r"TRUNCATEs+TABLE", "禁止清空数据库表"),
DenyRule(r"UPDATEs+w+s+SETs+w+s*=", "无 WHERE 条件的 UPDATE 操作"),
DenyRule(r">s*/dev/sd[a-z]|dds+if=", "危险磁盘操作"),
DenyRule(r"chmods+777", "禁止设置 777 权限"),
]
def check_command(self, command: str, tool: str = "Shell") -> dict:
"""检查命令是否安全"""
# 1. 硬拒绝规则
for rule in self.deny_rules:
if re.search(rule.pattern, command, re.IGNORECASE):
self._log("deny", tool, command, rule.reason)
return {
"allowed": False,
"reason": rule.reason,
"action": "deny"
}
# 2. 速率限制(每分钟最多执行 N 个写入操作)
if tool in ("FileWrite", "Shell") and self._is_rate_limited(tool):
self._log("rate_limit", tool, command, "速率限制触发")
return {
"allowed": False,
"reason": "操作过于频繁,请稍后再试",
"action": "rate_limit"
}
# 3. 高风险操作标记,需要人工确认
risk_level = self._assess_risk(command, tool)
if risk_level > 0.7:
self._log("ask", tool, command, f"高风险操作(风险分: {risk_level:.2f})")
return {
"allowed": True,
"need_approval": True,
"reason": f"高风险操作(风险分: {risk_level:.2f}),请确认",
"action": "ask"
}
self._log("allow", tool, command, "自动放行")
return {"allowed": True, "action": "allow"}
def _assess_risk(self, command: str, tool: str) -> float:
"""风险评估:0(安全)到 1(极高风险)"""
score = 0.0
risk_signals = [
(r"DELETEs+FROM", 0.4),
(r"ALTERs+TABLE", 0.5),
(r"gits+push", 0.3),
(r"npms+publish", 0.6),
(r"sudos+", 0.5),
(r"kills+-9", 0.4),
(r".env", 0.3),
(r"production|prod", 0.6),
(r"database|dbs+:", 0.4),
(r"--force|--no-verify", 0.5),
]
for pattern, weight in risk_signals:
if re.search(pattern, command, re.IGNORECASE):
score += weight
return min(score, 1.0)
def _is_rate_limited(self, tool: str) -> bool:
"""简单的速率限制"""
from time import time
now = time()
key = f"{tool}_write"
self.rate_limiter[key] = [
t for t in self.rate_limiter.get(key, [])
if now - t < 60
]
# 每分钟最多 10 次写入操作
return len(self.rate_limiter[key]) >= 10
def _log(self, action: str, tool: str, command: str, reason: str):
"""审计日志"""
from time import time
self.audit_log.append({
"time": time(),
"action": action,
"tool": tool,
"command": command[:200],
"reason": reason
})
# 使用示例
guard = AgentGuard()
result = guard.check_command("rm -rf /data/backup")
# {'allowed': False, 'reason': '禁止删除根目录', 'action': 'deny'}
result = guard.check_command("npm publish --access public")
# {'allowed': True, 'need_approval': True, 'reason': '高风险操作,请确认', 'action': 'ask'}
result = guard.check_command("git status")
# {'allowed': True, 'action': 'allow'}
这个 Guard 虽然简单,但把 Claude Code 的五层核心思想都体现出来了:
1. Deny Rules — 硬拒绝规则,模式匹配最危险的命令
2. 风险评估 — 根据命令内容动态打分,决定是否需要人工确认
3. 速率限制 — 防止 Agent 短时间内执行大量操作
4. 审计日志 — 所有操作全量记录,出了事能追溯
5. 可扩展 — 给每层加钩子,和你的项目深度集成
Harness Engineering:2026 年 AI 安全的范式
如果你觉得上面那个 Guard 还不够体系化,那得了解一下 2026 年最火的 AI 工程化概念——Agent Harness Engineering(智能体驾驭工程)。
这个概念源自一个接地气的比喻:AI Agent 是一匹马,Harness 是缰绳。没有缰绳的马再强壮也无法驾驭。
一个成熟的 Harness 架构包含三层:
缰绳层(Reins)—— 控制方向
├── 工具权限管控
├── 行为边界定义
└── 拒绝策略
马鞍层(Saddle)—— 承载负载
├── 上下文注入
├── 系统提示管理
└── 会话状态
赛道层(Track)—— 规定路径
├── 工作流编排
├── 生命周期钩子
└── 执行顺序约束
- 缰绳层回答的是「能不能做」——权限、边界、拒绝规则
- 马鞍层回答的是「怎么做」——注入上下文、约束行为模式
- 赛道层回答的是「按什么顺序做」——编排工作流、确保关键步骤不被跳过
这三层合在一起,就构成了一个 AI Agent 的完整安全边界。Claude Code 的权限系统主要覆盖缰绳层,而像 LangGraph、AG2 这类框架则重点实现了赛道层。
给团队的 5 条实操建议
看完这些设计,你的团队现在就能开始做:
1. 拿到 Agent 就用 Docker 容器跑。最低成本的隔离方案,即使 Agent 把宿主机搞炸了,容器重启就恢复。Claude Mode 的 sandbox 模式就是这个思路。
2. 写一个 Deny Rules 清单。和团队一起坐下来,列出所有「Agent 绝对不能做的事情」,比如删根目录、强制推送到主分支、操作生产数据库。把这些规则硬编码到你的 Agent 框架里。
3. 所有操作全量审计。Agent 执行了什么命令、改了什么文件、调了什么 API,全部写进审计日志。出了事才知道怎么回滚。
4. 引入人肉审批环节。高风险操作(git push –force、npm publish、数据库写操作)必须人工确认。可以参考 GitHub 的 protected branch 逻辑——Agent 可以提 PR,但合入主分支需要人来点按钮。
5. 给 Agent 设置「行为预算」。和你写 CI/CD pipeline 时设置超时限制一样,给 Agent 的执行设置限额——这条任务最多读 50 个文件、最多改 10 个文件、最多跑 3 条命令。超了就得重新评估。
收尾
AI 编程 Agent 的「能力越强,越需要约束」这个悖论,其实和我们做前端工程化是一个道理:你不可能在代码上线前才检查质量,而是从提交那一刻起就开始「门禁」。Agent 安全也一样——不是出了问题再去堵窟窿,而是从 Agent 设计的第一天起就把它框在安全边界里。
我给团队的建议是:先把你 Agent 的 deny rules 写出来,哪怕只是 10 条正则。这个动作本身就是一次安全心智模型的建立。等 Agent 真的开始跑了,你会发现这些规则远远不够——但至少你不会成为那 62% 里的一个翻车案例。
如果你现在还没开始关注 AI Agent 安全,那今天读了这篇文章,至少可以先给自己定一条铁律:所有给 AI Agent 的执行环境,都要先过安全代理这关。
评论区
登录后可评论。












