---
title: "危险权限治理与 sandbox 实践"
wiki: cli
category: "最佳实践"
slug: dangerous-permissions-and-sandbox
url: https://learnagent.wiki/cli/cards/dangerous-permissions-and-sandbox
tags: ["安全", "权限", "sandbox", "dangerously-skip-permissions", "CI", "团队"]
last_updated: 2026-04-22
reading_time: 16
---

> CLI Agent 跑在终端里，比 IDE 插件、网页版多了一项致命的能力——**它可以直接拿到 shell**。Claude Code 跑 `Bash`、Codex CLI 跑 `shell`、Gemini CLI 跑 `run_shell_command`，本质上都是把模型生成的命令塞进你电脑的进程树里执行。一旦你为了"少敲几下回车"而把权限放开到底，Agent 就有能力 `rm -rf` 你的家目录、把 `.env` 里的 token 发到外网、把 SSH 私钥写进一段它觉得"很合理"的 commit。这就是 **"危险权限"** 这个词在 CLI Agent 语境下真正的含义。

# 危险权限治理与 sandbox 实践

## 基础概念

CLI Agent 跑在终端里，比 IDE 插件、网页版多了一项致命的能力——**它可以直接拿到 shell**。Claude Code 跑 `Bash`、Codex CLI 跑 `shell`、Gemini CLI 跑 `run_shell_command`，本质上都是把模型生成的命令塞进你电脑的进程树里执行。一旦你为了"少敲几下回车"而把权限放开到底，Agent 就有能力 `rm -rf` 你的家目录、把 `.env` 里的 token 发到外网、把 SSH 私钥写进一段它觉得"很合理"的 commit。这就是 **"危险权限"** 这个词在 CLI Agent 语境下真正的含义。

具体来说，"危险权限"通常指三类被默认询问、可以一键绕过的能力：

1. **任意 shell 命令** — `Bash` / `shell` 工具本身
2. **任意写入** — `Write` / `Edit` 对文件系统的修改，尤其是 repo 之外的路径
3. **任意网络出站** — `WebFetch` / `curl` / `wget` 把数据传到外部域名

CLI Agent 默认会在执行这些动作前弹窗征求人类同意，这是为了挡住两条最高频的攻击路径：**模型自己的判断失误**（"我以为这个文件没用"）和 **prompt injection**（一段 README 里的恶意指令骗 Agent 把 `~/.aws/credentials` 上传出去）。把权限"绕过"的代价，就是把这两条防线一起拆掉。

绕过的代价不是抽象的。2025 年 10 月，开发者 Mike Wolak 跑 Claude Code 时开了 `--dangerously-skip-permissions`，Agent 在一次"清理临时文件"中执行了从 `/` 开始的 `rm -rf`，日志里几千行 `Permission denied: /bin /boot /etc`，最终把这台机器上所有用户可写文件全部清空。还有一类更隐蔽的事故：2026 年 Johns Hopkins 的研究者用一段 prompt injection 同时劫持了 Claude Code Security Review、Gemini CLI Action、GitHub Copilot 三个跑在 GitHub Actions 里的 Agent，让它们把仓库 secret 发给了攻击者控制的服务。**这两类事故的共同点都是"权限太大 + 沙箱太薄"**。

### 治理纵深防御层级

危险权限治理不是一个开关，而是一组叠加的层。下图是当前业界（参考 Anthropic 官方 devcontainer、trailofbits 的 sandbox 模板、NVIDIA 的 Agentic Workflow 安全指南）收敛出来的纵深防御模型：

```mermaid
graph TB
    subgraph L5["L5 团队规范层（settings.json + code review）"]
        T1[强制 allowedTools 白名单]
        T2[禁用 bypassPermissions in CI]
        T3[secret 集中管理 + 最小权限]
    end
    subgraph L4["L4 进程内拦截层（hooks）"]
        H1[PreToolUse: 拦截 rm -rf / curl 外网]
        H2[PostToolUse: 审计 + 留痕]
    end
    subgraph L3["L3 OS 沙箱层（Firejail / bubblewrap / seccomp）"]
        O1[限制系统调用]
        O2[限制可见目录]
    end
    subgraph L2["L2 容器隔离层（devcontainer / Docker / VM）"]
        C1[network firewall 白名单]
        C2[只挂载项目目录]
        C3[非 root 用户]
    end
    subgraph L1["L1 物理/账号隔离层（独立机器、独立云账号）"]
        P1[与生产、敏感数据物理隔离]
    end
    L5 --> L4 --> L3 --> L2 --> L1
```

每一层都不是万能的。L4 hooks 拦不住"hooks 配置文件本身被改"；L2 容器拦不住"挂载进来的 `.env` 被读出去再 POST 出去"；L1 隔离拦不住"开发者自己把生产 token 拷到沙箱机器上"。**真正的安全来自这些层之间的冗余**——某一层失守时，下一层还兜得住。

### 核心要素

| 要素 | 作用 | 失守会怎样 |
|------|------|----------|
| **permission mode** | Claude Code 的权限模式：`default / acceptEdits / plan / bypassPermissions` | 错开 `bypassPermissions` 会把所有提示拆掉 |
| **allowedTools / deniedTools** | 在 settings.json 里硬白/黑名单 | 名单不写或写错时 hook 是最后一道闸 |
| **hooks** | PreToolUse / PostToolUse 等生命周期钩子 | 可以拦住"绕过权限提示后的具体命令" |
| **container/sandbox** | devcontainer / Docker / Firejail 的进程与文件隔离 | 拦不住挂载进容器的 secret 被外传 |
| **network egress 控制** | iptables / 防火墙白名单 | 拦不住通过白名单域名（如 GitHub）的隐写攻击 |

## 基础用法

下面四段是最常用的配置实操，按 "团队 settings → 容器隔离 → CI 场景 → hook 拦截" 的顺序逐层加固。

### 1. 团队级 settings.json 模板

把 settings.json 提交进仓库（路径 `.claude/settings.json`），让每个团队成员一启动 Claude Code 就拿到一致的安全基线。这一份模板覆盖了 95% 团队的实际需要：

```json
{
  "permissions": {
    "defaultMode": "default",
    "allow": [
      "Read",
      "Edit(./src/**)",
      "Edit(./tests/**)",
      "Bash(npm run test:*)",
      "Bash(npm run lint:*)",
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)"
    ],
    "deny": [
      "Bash(rm -rf:*)",
      "Bash(sudo:*)",
      "Bash(curl:*)",
      "Bash(wget:*)",
      "Bash(chmod 777:*)",
      "Bash(git push --force:*)",
      "Edit(./.env*)",
      "Edit(./**/credentials*)",
      "Edit(/etc/**)",
      "Edit(~/.ssh/**)",
      "WebFetch"
    ]
  },
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [{ "type": "command", "command": ".claude/hooks/bash-guard.sh" }] }
    ]
  }
}
```

要点：

- `defaultMode` 不要写成 `bypassPermissions`，团队基线必须是"默认要问"。
- `allow` 用细粒度的工具+参数模式，比起整段 `Bash` 放开靠谱得多。
- `deny` 列表要把"破坏性 + 提权 + 外传"三类常见动作堵死，注意 `:*` 是 Claude Code 的通配语法。
- 拦截脚本走 hooks，可以做更复杂的判断（见后文）。

### 2. devcontainer 容器隔离

Anthropic 官方推荐的隔离方式是 [Development Containers](https://code.claude.com/docs/en/devcontainer)，可以一行 feature 引入。下面这份 `.devcontainer/devcontainer.json` 是 Anthropic 官方模板的精简版，重点在 **firewall 白名单 + 非 root 用户**：

```json
{
  "name": "claude-code-sandbox",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:20",
  "features": {
    "ghcr.io/anthropics/devcontainer-features/claude-code:1": {}
  },
  "remoteUser": "node",
  "mounts": [
    "source=${localWorkspaceFolder},target=/workspace,type=bind"
  ],
  "runArgs": [
    "--cap-add=NET_ADMIN",
    "--cap-add=NET_RAW"
  ],
  "postCreateCommand": "sudo /usr/local/bin/init-firewall.sh",
  "containerEnv": {
    "ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}"
  }
}
```

`init-firewall.sh` 默认拒绝所有出站，再放行 npm registry、GitHub API、Anthropic API 等少数白名单域名。这样即便 Agent 在容器里被 prompt injection 控制，也无法把数据 POST 到攻击者的服务器。容器跑 `--dangerously-skip-permissions` 的代价被显著降低——但请记住官方明确写过的一句话：**容器不能阻止 Agent 把容器内能看到的 Claude Code 凭证、`.env` 文件外传**。所以即便在容器里，secret 也不该裸挂进去。

GitHub Codespaces 直接吃这份 devcontainer 配置；Cursor、VS Code 也都内置 devcontainer 支持，团队基线只用维护一份。

### 3. CI 场景：GitHub Actions runner

CI 是危险权限的高发地：因为 CI 没有人盯着，开发者倾向于直接开 `--dangerously-skip-permissions`。下面是一份"在 PR 上跑 Claude Code 自动 review"的最小安全模板：

```yaml
name: claude-review
on:
  pull_request:
    types: [opened, synchronize]
permissions:
  contents: read
  pull-requests: write
jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - name: run claude code in sandboxed mode
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # 不开 dangerously-skip-permissions，依赖 settings.json 里的 allow 名单
          npx -y @anthropic-ai/claude-code \
            --settings .claude/ci-settings.json \
            --print "review the diff and post review comments" \
            --output-format stream-json
```

关键安全点：

- `permissions:` 用最小化的 GITHUB_TOKEN scope，**不要默认 write-all**。
- `persist-credentials: false` 防止 GITHUB_TOKEN 被写进 `.git/config` 后被 Agent 读到。
- `timeout-minutes` 兜底防 Agent 死循环跑爆 minute。
- 不要在 CI 里写 `--dangerously-skip-permissions`：CI 的"无人值守"恰恰是**最不该绕过权限**的场景。
- secret 只通过 env 传入，不要落盘。

### 4. PreToolUse hook 拦截脚本

settings.json 的 `deny` 名单是字符串匹配，覆盖不了"`bash -c 'r''m -rf /'`"这种变形。真正可靠的兜底是 hook 脚本——它在 Agent 想跑命令、命令真的下到 shell 之前那一瞬间执行，可以做完整的 AST/正则判断。下面是一份 `.claude/hooks/bash-guard.sh` 示例：

```bash
#!/usr/bin/env bash
# PreToolUse hook：在 Bash 工具真正执行前拦截高危命令。
# Claude Code 会把工具调用的 JSON 通过 stdin 传进来。
set -euo pipefail

input="$(cat)"
cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty')"

# 高危命令模式（按需扩充，建议团队共维一份）
deny_patterns=(
  'rm[[:space:]]+(-[a-zA-Z]*r[a-zA-Z]*[[:space:]]|--recursive)'
  'sudo[[:space:]]'
  'chmod[[:space:]]+777'
  'curl[[:space:]].*\|[[:space:]]*(sh|bash|zsh)'
  'wget[[:space:]].*\|[[:space:]]*(sh|bash|zsh)'
  'git[[:space:]]+push[[:space:]].*--force'
  ':\(\)\{[[:space:]]*:\|:&[[:space:]]*\};:'   # fork bomb
  '/dev/(sda|nvme|tcp)'
  '\.ssh/(id_|authorized_)'
  '\.aws/credentials'
)

for pat in "${deny_patterns[@]}"; do
  if [[ "$cmd" =~ $pat ]]; then
    # exit 2 是 Claude Code 约定的"阻断"信号：阻止此次 tool 调用，并把 stderr 反馈给模型
    echo "blocked by bash-guard: matches /$pat/" >&2
    exit 2
  fi
done

exit 0
```

退出码语义来自 [Claude Code hooks reference](https://code.claude.com/docs/en/hooks)：**exit 2 是阻断信号**，Agent 会拿到 stderr 内容并知道"刚才那条命令被拦了，请换一个思路"。这一层兜底的好处是**模型再怎么被 prompt injection 也绕不过**——hook 是 shell 进程，不是 prompt，无法被劝说。

## 同类工具对比

四款主流 CLI Agent 在权限/沙箱设计上有显著差异，理解差异有助于团队按工具特性配规范。

| 工具 | 权限模型 | 默认沙箱 | "全权限"模式 | 进程内拦截能力 | 推荐用法 |
|------|---------|---------|-------------|---------------|---------|
| **Claude Code** | 4 档：default / acceptEdits / plan / bypassPermissions | 无（依赖容器） | `--dangerously-skip-permissions`；2026-03 起官方推荐用 `auto mode` 替代 | hooks（PreToolUse/PostToolUse 等 8 类）+ allow/deny 名单 | 配 devcontainer + hooks 双层 |
| **Codex CLI** | 两轴：approval policy × sandbox mode | **有**：默认 sandbox（macOS 用 Seatbelt，Linux 用 Landlock+seccomp） | `--full-auto`，但仍在 sandbox 内 | sandbox 内 syscall 限制 + exec_policy | 直接信任默认沙箱即可 |
| **Gemini CLI** | 4 档：default / auto-edit / yolo / sandbox | 无（可选 `--sandbox`） | `--yolo`，**只能命令行传，不能写进 settings 默认** | sandbox 模式（Docker/Podman）+ trusted folders | 长期运行务必加 `--sandbox` |

**核心区别**：Codex CLI 的设计哲学是"**沙箱在前，权限在后**"——即便开了 `--full-auto`，还是被 OS 级 sandbox 兜底，所以实际事故率最低；Claude Code 走的是"**协议在前，沙箱在外**"——内置 hooks/permissions 协议非常完备，但 OS 级隔离要靠用户自己加 devcontainer；Gemini CLI 则在 yolo 模式上做了一个有意思的克制——`yolo` 不能写进 settings.json 的默认值，必须每次显式 `--yolo`，意在用"麻烦"对抗"惯性"。

## 常见误区

| 误区 | 准确理解 |
|------|---------|
| **以为 `--dangerously-skip-permissions` 在 CI 里安全**（"反正没人在键盘前看着，不绕过就走不动") | CI 才是最不该绕过的场景：无人值守 + 长时间持有 secret + 网络可达，恰好凑齐了攻击三要素。CI 应该用更细的 allowedTools 名单，而不是更松的开关 |
| **以为容器隔离能防 secret 外传** | 容器只隔离进程和文件系统。如果你把 `~/.aws`、`.env` 挂进容器，Agent 在容器里照样能读到然后通过白名单域名（GitHub raw、issue 评论）外传。Anthropic 官方文档明确写过这一点 |
| **以为 Firejail 是 Linux 上的银弹** | Firejail 需要 setuid root，配置语言冷僻，whitelisting 粒度只到 `/home`、`/tmp` 这一级，且只沙箱 Agent 进程本身——Agent 调起的子进程（npm、make、gcc）经常需要打破沙箱才能跑通，结果是用户被频繁的拒绝提示训练成"全部允许"。Firejail 适合作为**额外的一层**，不是主防线 |
| **以为 settings.json 的 allow/deny 写得够细就够了** | allow/deny 是字符串匹配，对付不了 `bash -c '$(echo cm0gLXJmIC8K | base64 -d)'`、变量拼接、shell 函数包装。**hooks 是必须的兜底**，因为 hook 脚本拿到的是已经展开的命令字符串 |
| **以为"只读权限不会出事"** | 读权限就是 secret 外传的入口。Agent 能读到的 token、history、`.git/config` 里的 PAT、`~/.gitconfig` 里的邮箱，都可以经由 Agent 的合法网络请求被发出去——这是 prompt injection 类攻击最常见的路径 |
| **以为升级 Claude Code 自动获得新安全特性** | 历史上 Claude Code 0.x 多次默认行为变更（权限模式默认值、hook 字段重命名），团队 settings.json 不跟着升就会失效。Anthropic 2026-03-31 那次源码 sourcemap 泄露，也提醒团队**不要把 Agent 当作不会出问题的黑盒**，关注 release note、订阅安全公告 |
| **以为 hook 配置不会被改** | hook 配置写在 `.claude/settings.json` 里，Agent 本身有权 Edit 这个文件。**必须把 settings.json 加进 deny 名单**：`Edit(.claude/**)`，否则一段 prompt injection 就能让 Agent 关掉自己的 guard |

## 优劣势分析

| 优势（建立纵深防御后） | 劣势（即便建好了也要承认） |
|------|------|
| **明显降低事故面**：rm -rf 类、git push --force 类、外传 secret 类的常见 hot path 被堵死 | **完全的 prompt injection 防御目前不存在**：模型对内容的理解能力本身就是攻击面 |
| **团队基线一致**：settings.json 进仓库后，新成员开箱即合规 | **维护成本高**：deny 名单和 hook 模式需要随工具升级、攻击手法变化持续维护 |
| **CI/CD 可审计**：所有命令通过 hook 留痕，事后可追溯 | **会牺牲一定开发效率**：高强度的拦截会出现"明明我想跑这条命令也被拦了"的体验损耗 |
| **多 Agent 通用**：Claude Code 的 hook 思路、Codex 的 sandbox 思路可以混用 | **隔离粒度有上限**：OS 级沙箱拦不住"挂载进容器的 secret 被合法读取再合法外传" |
| **官方支持持续加强**：Anthropic 在 2026-03 推出 auto mode 用分类器替代 dangerous bypass，趋势利好 | **生态不一致**：四款主流 CLI Agent 的权限模型差异大，团队规范需要按工具一一适配 |

## 思考题

<details>
<summary>初级：为什么"在 CI 里开 --dangerously-skip-permissions 反而更危险"？</summary>

**参考答案：**

危险权限治理的本质是"在出事前有人或机制能阻断"。CI 同时拥有三件事：(1) **没有人在键盘前**，模型决定要执行就会执行；(2) **长时间持有高权限 token**，包括仓库写权限、云服务凭证、包管理 publish token；(3) **完全的网络可达性**，可以向任意外网发请求。

把权限提示一关，等于把"模型在错误判断"和"prompt injection 在仓库 README 里植入恶意指令"这两条攻击路径全部失防。Johns Hopkins 2026 年那次研究就是用一段 issue 评论，让跑在 GitHub Actions 里的 Claude Code Security Review、Gemini CLI Action、Copilot 同时把仓库 secret POST 给了攻击者。

正确做法是反过来：**CI 是 allowedTools 应该写得最严的场景**，而不是最松。CI 跑的任务是固定的，能用细名单写死就一定要写死。

</details>

<details>
<summary>中级：为什么 Firejail / Docker 容器都"不能完全阻止 secret 外传"？什么情况下需要再加一层？</summary>

**参考答案：**

OS 级沙箱（Firejail / Landlock / seccomp）和容器级隔离（Docker / devcontainer）都是在**进程边界**上做隔离——它们能保证 Agent 看不到沙箱外的文件、调不到沙箱外的命令。但是 secret 外传往往不是"突破沙箱"，而是"在沙箱里把合法读到的东西通过合法的网络出口发出去"。

举两个具体场景：(1) 你把 `~/.aws/credentials` 挂进 devcontainer 是为了 Agent 能调 AWS API，但同样的内容也可以被读出后塞进一个 `gh issue comment`；(2) 容器的 firewall 白名单放行了 `api.github.com`，但攻击者完全可以让 Agent 把 secret 编码到一个 GitHub gist 的内容里 POST 出去——出口是合法的，内容是 secret 的。

什么情况下需要再加一层？三种：(a) **secret 不放进沙箱**，改用临时 token、按需注入、用完即销，从源头消除可读性；(b) **加 PostToolUse hook 做出站审计**，对所有 WebFetch/curl/git push 做 payload 哈希记录，事后能追溯；(c) **物理/账号隔离**，Agent 运行在独立云账号、独立 GitHub Org，与生产 secret 域物理无交集，即便外传也只能拿到玩具 token。

记住一句话：**沙箱降低攻击面，凭证管理才决定爆炸半径**。

</details>

<details>
<summary>进阶：为什么 hook 也不是终极方案？还有哪些剩余风险？怎么对冲？</summary>

**参考答案：**

hook 比 settings.json 的 allow/deny 强，是因为它拿到的是展开后的命令、能跑任意脚本判断；但它仍有几个根本短板。

**短板一：自我修改攻击。** hook 配置写在 `.claude/settings.json` 里，而 Agent 有权 Edit 这个文件。一段 prompt injection 完全可以是"先把 .claude/settings.json 里的 hooks 字段删掉，再 rm -rf"。对冲方式有三层：(a) settings.json 加进文件级 deny；(b) 把关键 hook 移到仓库外、Git 不可达的位置（如 `~/.claude/global-hooks/`）；(c) PostToolUse 监控 settings.json 是否被改，触发即告警并 kill session。

**短板二：模式匹配不可能枚举完所有变形。** `rm -rf` 可以写成 `\rm -rf`、`bash -c 'r''m -rf'`、`echo cm0gLXJmIC8 | base64 -d | bash`、调用一个看起来无害的 npm 包内部跑 rm。对冲方式不是堆模式，而是**改变防御层级**——把 rm 这个二进制本身在沙箱里换成一个被包装过的 wrapper，或干脆用只读文件系统挂载（read-only bind mount）让 rm 在物理上无效。

**短板三：hook 只看命令，不看意图。** 一条 `git push origin main` 在测试仓库无害，在生产仓库灾难。要做到"按上下文判断"，需要把 hook 升级成调用 LLM 二次审核（Anthropic 2026-03 发布的 auto mode 做的就是这件事——一个独立的 Sonnet 4.6 分类器评估"作用域升级 / 不受信基础设施 / prompt injection"三类风险）。但这又引入新成本：审核延迟、二次模型也可能被 prompt injection。

**结论：** 安全是不断**把单点防御变成纵深防御**的过程。hook 是必要的一层，但它需要和容器、网络白名单、凭证最小化、事后审计、独立环境一起组合，才能把剩余风险压到可接受的水位。承认"没有终极方案"本身，就是这道题最重要的答案。

</details>

## 参考资料

1. Claude Code 官方权限模式文档：<https://code.claude.com/docs/en/permission-modes>（查询日期 2026-04-22）
2. Claude Code 官方 devcontainer 文档：<https://code.claude.com/docs/en/devcontainer>（查询日期 2026-04-22）
3. Claude Code Hooks 完整参考：<https://code.claude.com/docs/en/hooks>（查询日期 2026-04-22）
4. Anthropic 官方公告："auto mode: a safer way to skip permissions"（2026-03-24）：<https://www.anthropic.com/engineering/claude-code-auto-mode>
5. Trail of Bits 安全沙箱模板：<https://github.com/trailofbits/claude-code-devcontainer>
6. NVIDIA：Practical Security Guidance for Sandboxing Agentic Workflows：<https://developer.nvidia.com/blog/practical-security-guidance-for-sandboxing-agentic-workflows-and-managing-execution-risk/>
7. VentureBeat：Three AI coding agents leaked secrets through a single prompt injection（Johns Hopkins 研究复盘，2026）：<https://venturebeat.com/security/ai-agent-runtime-security-system-card-audit-comment-and-control-2026>
8. Help Net Security：29 million leaked secrets in 2025（GitGuardian 报告）：<https://www.helpnetsecurity.com/2026/04/14/gitguardian-ai-agents-credentials-leak/>
9. Codex CLI 沙箱机制说明：<https://developers.openai.com/codex/cli>（查询日期 2026-04-22）
10. Gemini CLI Sandboxing 文档：<https://geminicli.com/docs/cli/sandbox/>（查询日期 2026-04-22）
11. ksred 博客：Claude Code --dangerously-skip-permissions 安全使用指南：<https://www.ksred.com/claude-code-dangerously-skip-permissions-when-to-use-it-and-when-you-absolutely-shouldnt/>
12. SES 博客：AI Agents Deleting Home Folders? Run Your Agent in Firejail：<https://softwareengineeringstandard.com/2025/12/15/ai-agents-firejail-sandbox/>

---
*Source: https://learnagent.wiki/cli/cards/dangerous-permissions-and-sandbox*
*Markdown mirror of https://learnagent.wiki, served as text/markdown for LLM ingestion.*