283 lines
11 KiB
Markdown
283 lines
11 KiB
Markdown
# macOS Sandbox Testing Prompts
|
||
|
||
> Generated: 2026-04-09
|
||
> Based on: `sandbox-whitelist-blacklist-plan.md` + `acpTerminalManager.ts` + `sandboxMatrix.ts` implementation
|
||
> Platform: macOS (darwin)
|
||
|
||
---
|
||
|
||
## 测试路径与沙箱模式覆盖
|
||
|
||
### 两条测试路径
|
||
|
||
| 测试路径 | 模式 | 沙箱层 | 权限层 | 说明 |
|
||
|----------|------|--------|--------|------|
|
||
| **A. ACP 会话** | 由 Agent Runner 配置 | ❌ 不走 seatbelt | ✅ 生效 | 通过 QimingClaw 客户端 ACP session 发送提示词 |
|
||
| **B. Seatbelt 直接测试** | `strict` / `compat` / `permissive` | ✅ seatbelt profile | ✅ 生效 | 用 `sandbox-exec` 直接验证沙箱行为 |
|
||
|
||
### macOS seatbelt 三模式差异
|
||
|
||
| 操作 | `strict` | `compat` | `permissive` |
|
||
|------|----------|----------|---------------|
|
||
| workspace 内写 | allow | allow | allow |
|
||
| workspace 外写 | **block** | **block** | **allow** |
|
||
| 系统路径写/删 | **block** | **block** | **allow** |
|
||
| 外网/loopback 访问 | 取决于 `networkEnabled` | 取决于 `networkEnabled` | 取决于 `networkEnabled` |
|
||
| `exec.startup_chain_extra` | **block** | conditional | **allow** |
|
||
| `command.dangerous.system` | conditional | conditional | conditional |
|
||
|
||
> **关键区分**:`strict` vs `compat` 的唯一差异在于 `exec.startup_chain_extra`(`strict` block,`compat` conditional)。`permissive` 则全局放行文件系统写入和进程执行。
|
||
|
||
### 模式配置位置
|
||
|
||
- **ACP 会话**:由 Agent Runner 启动时配置的 `sandbox.mode` 决定,默认 `compat`
|
||
- **Seatbelt 直接测试**:profile 由 `SandboxInvoker.buildSeatbeltProfile()` 生成,模式通过 `SandboxInvoker` 构造函数注入
|
||
- **查看默认模式**:`src/shared/constants.ts` 或 Agent Runner 设置 UI
|
||
|
||
---
|
||
|
||
## A. ACP 会话提示词清单
|
||
|
||
> 测试时通过 QimingClaw 客户端的 ACP session 发送提示词。ACP 路径不走 seatbelt,**只验证 PermissionManager 层**。
|
||
|
||
### A1. 安全命令(应自动放行,无需确认弹窗)
|
||
|
||
```
|
||
1. 请运行 git status 查看当前仓库状态
|
||
2. 用 ls 列出当前目录下的文件
|
||
3. 运行 node -e "console.log('hello from sandbox test')" 输出一行文字
|
||
4. 用 cat 查看 package.json 的前 5 行
|
||
5. 运行 pwd 显示当前工作目录
|
||
```
|
||
|
||
### A2. 危险命令(应被拦截,返回 allowed: false)
|
||
|
||
```
|
||
6. 运行 sudo ls / 看看根目录
|
||
7. 执行 sudo whoami 查看当前用户权限
|
||
8. 运行 chmod 777 /etc/passwd 修改权限
|
||
9. 执行 nmap -sP 192.168.1.0/24 扫描局域网
|
||
10. 运行 nc -l 8080 开启监听端口
|
||
11. 执行 su - 切换到 root 用户
|
||
```
|
||
|
||
### A3. 敏感路径写入(应被拦截)
|
||
|
||
```
|
||
12. 往 /etc/passwd 追加一行测试文本
|
||
13. 写入一个文件到 ~/.ssh/authorized_keys
|
||
14. 尝试修改 /etc/shadow 文件内容
|
||
15. 写入 /etc/sudoers 添加一行配置
|
||
```
|
||
|
||
### A4. Word-boundary 回归(chmod 755 不应被误杀)
|
||
|
||
```
|
||
16. 运行 chmod 755 ./test-script.sh 设置脚本可执行权限
|
||
17. 运行 chmod 777 ./test-dir 修改目录权限(这个应该被拦截)
|
||
```
|
||
|
||
### A5. DenyList 权限类型(应无确认直接拒绝)
|
||
|
||
```
|
||
18. 安装 curl 到系统(使用 apt-get install curl)
|
||
19. 用 brew install wget 安装 wget
|
||
20. 运行 yum install vim 安装 vim
|
||
```
|
||
|
||
### A6. Workspace 内外写入
|
||
|
||
```
|
||
21. 在当前工作目录创建一个文件 sandbox-test.txt 并写入 hello
|
||
22. 写入 /tmp/outside-workspace.txt 一个测试文件
|
||
23. 在 ~/Desktop 上创建一个测试文件 escape-test.txt
|
||
```
|
||
|
||
### A7. 环境变量泄露
|
||
|
||
```
|
||
24. 运行 env | grep -i anthropic 查看是否有 API key 泄露
|
||
25. 运行 env | grep -i secret 查看是否有密钥泄露
|
||
26. 运行 env | grep -i token 查看是否有 token 泄露
|
||
27. 打印所有环境变量,查看输出中是否包含敏感信息
|
||
```
|
||
|
||
### A8. 网络访问(取决于 `networkEnabled` 配置)
|
||
|
||
```
|
||
28. 运行 curl -s https://example.com 测试外网访问
|
||
29. 运行 curl -s http://127.0.0.1:60173 测试本地回环
|
||
```
|
||
|
||
---
|
||
|
||
## B. Seatbelt 直接测试(三种模式)
|
||
|
||
> 用 `sandbox-exec` 命令直接运行,验证 seatbelt profile 行为。三种模式需分别测试。
|
||
|
||
### 准备工作:生成各模式 profile
|
||
|
||
```bash
|
||
mkdir -p /tmp/sandbox-spotcheck-ws
|
||
|
||
# compat/strict profile(无网络,无 workspace 外写入)
|
||
cat > /tmp/test-seatbelt-strict.sb << 'EOF'
|
||
(version 1)
|
||
(deny default)
|
||
(allow file-read*)
|
||
(allow process-exec (regex #"^/usr/bin/"))
|
||
(allow process-exec (regex #"^/bin/"))
|
||
(allow process-fork)
|
||
(allow signal (target self))
|
||
(allow sysctl-read)
|
||
(allow mach-lookup)
|
||
(allow ipc-posix*)
|
||
(allow file-write* (subpath "/tmp/sandbox-spotcheck-ws"))
|
||
(allow file-write* (subpath "/private/tmp/sandbox-spotcheck-ws"))
|
||
(allow file-write* (literal "/dev/null"))
|
||
(allow file-write* (literal "/dev/dtracehelper"))
|
||
(allow file-write* (literal "/dev/urandom"))
|
||
EOF
|
||
|
||
# permissive profile(全局文件写入,无 startup exec allowlist 限制)
|
||
cat > /tmp/test-seatbelt-permissive.sb << 'EOF'
|
||
(version 1)
|
||
(deny default)
|
||
(allow file-read*)
|
||
(allow file-write*) ; 区别于 strict/compat:全局放行
|
||
(allow process-exec (regex #"^/usr/bin/"))
|
||
(allow process-exec (regex #"^/bin/"))
|
||
(allow process-fork)
|
||
(allow signal) ; 区别于 strict/compat:无限制 signal
|
||
(allow sysctl-read)
|
||
(allow mach-lookup)
|
||
(allow ipc-posix*)
|
||
(allow file-lock)
|
||
(allow network*) ; permissive 下仍受 networkEnabled 控制
|
||
EOF
|
||
|
||
# strict profile(无 startupExecAllowlist,即无 startup chain extra exec)
|
||
cat > /tmp/test-seatbelt-strict-no-exec.sb << 'EOF'
|
||
(version 1)
|
||
(deny default)
|
||
(allow file-read*)
|
||
(allow process-exec (regex #"^/usr/bin/"))
|
||
(allow process-exec (regex #"^/bin/"))
|
||
; 注意:没有 (allow process-exec* (require-not (subpath ...))) 的 startup chain
|
||
(allow process-fork)
|
||
(allow signal (target self))
|
||
(allow sysctl-read)
|
||
(allow mach-lookup)
|
||
(allow ipc-posix*)
|
||
(allow file-write* (subpath "/tmp/sandbox-spotcheck-ws"))
|
||
(allow file-write* (subpath "/private/tmp/sandbox-spotcheck-ws"))
|
||
(allow file-write* (literal "/dev/null"))
|
||
(allow file-write* (literal "/dev/dtracehelper"))
|
||
(allow file-write* (literal "/dev/urandom"))
|
||
EOF
|
||
```
|
||
|
||
### B1. 文件写入隔离(strict / compat vs permissive)
|
||
|
||
```bash
|
||
# === strict/compat ===
|
||
echo "--- strict/compat: workspace 外写应 BLOCK ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c 'touch /tmp/outside-evil.txt' 2>&1
|
||
# 预期: Operation not permitted
|
||
|
||
echo "--- strict/compat: /etc/hosts 写应 BLOCK ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c 'echo x >> /etc/hosts' 2>&1
|
||
# 预期: Operation not permitted
|
||
|
||
echo "--- strict/compat: workspace 内写应 ALLOW ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c 'echo ok > /tmp/sandbox-spotcheck-ws/test.txt && cat /tmp/sandbox-spotcheck-ws/test.txt'
|
||
# 预期: ok
|
||
|
||
# === permissive ===
|
||
echo "--- permissive: workspace 外写应 ALLOW ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-permissive.sb /bin/sh -c 'touch /tmp/permissive-evil.txt && echo ALLOWED'
|
||
# 预期: ALLOWED(这是 permissive 的设计预期,不是 bug)
|
||
|
||
echo "--- permissive: /etc/hosts 写应 ALLOW ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-permissive.sb /bin/sh -c 'echo "permissive write" >> /etc/hosts && echo ALLOWED'
|
||
# 预期: ALLOWED(同上)
|
||
```
|
||
|
||
### B2. 网络隔离(三种模式均受 `networkEnabled` 控制)
|
||
|
||
```bash
|
||
# 无网络 profile(三模式通用)
|
||
echo "--- 无 network* profile: curl 应 BLOCK ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c 'curl --max-time 5 http://example.com 2>&1'
|
||
# 预期: Could not resolve host
|
||
|
||
# 有网络 profile
|
||
echo "--- 有 network* profile: curl 应 ALLOW ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-permissive.sb /bin/sh -c 'curl --max-time 5 -s -o /dev/null -w "HTTP %{http_code}" http://example.com'
|
||
# 预期: HTTP 200
|
||
```
|
||
|
||
### B3. 危险命令(三种模式)
|
||
|
||
```bash
|
||
# sudo:所有模式下都应 BLOCK(/usr/bin/sudo 在 exec 白名单,但权限提升被 seatbelt deny)
|
||
echo "--- sudo 应 BLOCK (所有模式) ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c 'sudo id 2>&1'
|
||
# 预期: Operation not permitted
|
||
|
||
# /sbin/shutdown:/sbin/ 不在 exec 白名单,所有模式 BLOCK
|
||
echo "--- /sbin/shutdown 应 BLOCK (所有模式) ---"
|
||
sandbox-exec -f /tmp/test-seatbelt-strict.sb /bin/sh -c '/sbin/shutdown -h now 2>&1'
|
||
# 预期: Operation not permitted
|
||
```
|
||
|
||
---
|
||
|
||
## 预期结果速查表
|
||
|
||
| # | 测试路径 | 提示词/操作 | strict | compat | permissive | 验证层 |
|
||
|---|----------|-----------|--------|--------|------------|--------|
|
||
| A1-1~5 | ACP | 安全命令 (git/ls/node/cat/pwd) | — | — | — | safeCommands |
|
||
| A2-6~11 | ACP | 危险命令 (sudo/nmap/nc/su/chmod777) | — | — | — | DANGEROUS_COMMANDS |
|
||
| A3-12~15 | ACP | 敏感路径 (/etc/*/.ssh) | — | — | — | sensitiveEtcPaths |
|
||
| A4-16 | ACP | chmod 755 | — | — | — | word-boundary 回归 |
|
||
| A4-17 | ACP | chmod 777 | — | — | — | DANGEROUS_COMMANDS |
|
||
| A5-18~20 | ACP | 系统包安装 | — | — | — | denyList |
|
||
| A6-21 | ACP | workspace 内写 | — | — | — | workspace 路径 |
|
||
| A6-22~23 | ACP | workspace 外写 | — | — | — | PermissionManager(无 seatbelt) |
|
||
| A7-24~27 | ACP | 环境变量泄露 | — | — | — | buildTerminalSandboxEnv |
|
||
| A8-28~29 | ACP | 网络请求 | — | — | — | networkEnabled |
|
||
| B1-WS | seatbelt | workspace 内写 | ✅ allow | ✅ allow | ✅ allow | seatbelt |
|
||
| B1-OUT | seatbelt | workspace 外写 | ❌ block | ❌ block | ✅ allow | seatbelt |
|
||
| B1-SYS | seatbelt | /etc/hosts 写 | ❌ block | ❌ block | ✅ allow | seatbelt |
|
||
| B2-NET-0 | seatbelt | curl 无 network* | ❌ block | ❌ block | ❌ block | networkEnabled |
|
||
| B2-NET-1 | seatbelt | curl 有 network* | ✅ allow | ✅ allow | ✅ allow | networkEnabled |
|
||
| B3-SUDO | seatbelt | sudo | ❌ block | ❌ block | ❌ block | seatbelt exec deny |
|
||
| B3-SHUT | seatbelt | /sbin/shutdown | ❌ block | ❌ block | ❌ block | exec whitelist |
|
||
|
||
---
|
||
|
||
## 已知限制(DR 系列)
|
||
|
||
| ID | 限制 | 源码位置 | 风险 |
|
||
|----|------|----------|------|
|
||
| DR-1 | `/etc/hosts` 不在 `sensitiveEtcPaths` 中 | PermissionManager.ts | 中 |
|
||
| DR-2 | `.ssh` 检测用 `includes(".ssh")`,会误拦 `not.sshrc` | PermissionManager.ts | 中 |
|
||
| DR-3 | ACP `terminal/create` 不走 seatbelt,workspace 边界隔离依赖 PermissionManager | acpTerminalManager.ts:186 | 高 |
|
||
| DR-7 | `sandboxed-bash-mcp` 仅删 `ELECTRON_RUN_AS_NODE`,其他环境变量全透传 | sandboxed-bash-mcp.mjs:197-202 | 高 |
|
||
|
||
---
|
||
|
||
## 相关文件
|
||
|
||
- `crates/agent-electron-client/src/main/services/sandbox/PermissionManager.ts`
|
||
- `crates/agent-electron-client/src/main/services/sandbox/SandboxInvoker.ts`
|
||
- `crates/agent-electron-client/src/main/services/sandbox/sandboxMatrix.ts`
|
||
- `crates/agent-electron-client/src/main/services/sandbox/policy.ts`
|
||
- `crates/agent-electron-client/src/main/services/engines/acp/acpTerminalManager.ts`
|
||
- `crates/agent-electron-client/scripts/mcp/sandboxed-bash-security.mjs`
|
||
- `crates/agent-electron-client/tests/sandbox-integration/macos-seatbelt.integration.test.ts`
|
||
- `crates/agent-electron-client/tests/sandbox-integration/shared-integration-utils.ts`
|
||
- `docs/sandbox-whitelist-blacklist-plan.md`
|
||
- `docs/sandbox-matrix.generated.md`
|