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 的执行环境,都要先过安全代理这关

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单