CodeMender默认开沙箱:--unrestricted什么时候才能用

安全 Agent 最容易出现的悖论是:

为了验证漏洞,
它需要执行更多命令。

但执行得越自由,
安全风险越大。

Google 的 CodeMender CLI 已把 process-level sandbox 设成默认行为。当前官方说明里,CLI 会默认把编译、测试、Shell 等 Agent 提议的命令放进 OS 级沙箱;同时仍保留:

--sandbox=false

以及:

--unrestricted

这类绕过方式。

真正值得工程团队关注的,不是某个 Flag,而是:

“验证能力更强”不能等于“在开发机上放弃执行边界”。

第一原则:默认沙箱必须是Secure Default

安全工具以前常见:

Sandbox:
可选

用户忘记开:

直接在本机执行

CodeMender 后来把沙箱改成默认启用,这个方向更合理。

所有 Agent Code Execution 都应该:

默认隔离
显式升级权限

而不是:

默认全权限
出问题再加限制

--unrestricted真正适合什么

它不应该成为:

“命令失败就加这个”

的通用解决办法。

更合理的使用场景只有:

专门隔离的验证环境
一次性VM
无生产Credential
受控网络
可销毁文件系统

也就是说:

环境本身已经是Sandbox

以后,进程级命令策略才可以适当放宽。

两层沙箱不要混

第一层:

Infrastructure Sandbox

例如:

gVisor
MicroVM
Disposable VM

第二层:

Process / Command Sandbox

限制 Agent 在环境里具体能做什么。

如果只有第二层:

一旦Command Policy被绕过
Host仍然危险

如果只有第一层:

Agent可能在Sandbox里破坏大量数据
或滥用网络

所以更稳:

Infrastructure Isolation
+
Command Policy

我会定义3个Execution Profile

profiles:

  inspect:
    shell: restricted
    network: deny
    filesystem: readonly

  verify:
    shell: sandboxed
    network: allowlist
    filesystem: workspace-write

  unrestricted-verify:
    shell: unrestricted
    network: deny-by-default
    infrastructure: disposable-vm

unrestricted-verify 的重点不是 unrestricted。

而是:

Disposable VM

Profile不能由模型自己选择

危险:

Agent:
“这个验证需要unrestricted。”
↓
自动升级

正确:

Agent提出需求
↓
Policy Engine
↓
Risk Classification
↓
人工/自动批准

模型只能:

request profile

不能:

grant itself profile

一个Execution Request

public record ExecutionRequest(
        String runId,
        String agentId,
        ExecutionProfile requestedProfile,
        String reason,
        String commandHash,
        RiskLevel risk) {
}

Policy 决定:

ALLOW
DENY
REQUIRE_APPROVAL

Verify和Exploit要分开

安全 Agent 的目标应该是:

证明问题存在

而不是:

最大化利用效果

所以验证用例尽量做:

Minimal Reproduction

例如:

触发异常
证明越权路径存在
证明不变量被破坏

不要为了“更确定”继续扩大影响。

我会给Verification定义Blast Radius

verification:

  max_files_modified: 5
  max_network_targets: 1
  max_runtime_seconds: 120
  max_processes: 128
  production_credentials: false

超过直接停止。

这比一句:

“请谨慎验证”

强得多。

网络必须默认Deny

安全验证最危险的环境之一是:

本机有公司VPN
Agent有Shell
网络全通

这时一个“验证”动作可能意外碰到:

真实内网
生产API
Metadata Endpoint

所以:

network=deny

应成为默认。

需要下载依赖:

Internal Mirror

需要验证 HTTP:

只开放目标测试服务

不要给验证环境生产Secret

即使网络隔离,也不要注入:

AWS_PROD_KEY
DATABASE_PROD_PASSWORD
GITHUB_ADMIN_PAT

验证环境用:

Synthetic Credential
Test Tenant
Mock Service

如果确实要访问受控真实系统:

短期Credential
最小Scope
只读优先

File System也要限制

安全 Agent 可能运行:

编译
测试
Patch

通常只需要项目 Workspace。

不应该看到:

~/.ssh
~/.aws
浏览器Cookie
整个Home

所以 Mount:

/project

就够。

不要:

-v $HOME:/home

Process Limit不能省

即使是沙箱,失控进程也能造成 DoS。

至少:

CPU
Memory
PID
Timeout
Stdout
Disk

全部有限额。

例如:

limits:
  cpu: 2
  memory: 2Gi
  pids: 256
  timeout: 180s
  disk: 4Gi
  stdout: 20Mi

为什么Stdout也要限

一个命令持续打印:

大量日志

可以拖垮:

Agent上下文
日志系统
网络
存储

所以超过:

20MiB

截断。

同时保留:

truncated=true

让 Agent 知道结果不完整。

unrestricted前一定要做Environment Attestation

不要只相信:

配置里写着isolated=true

执行前实际检查:

是不是Disposable VM
有没有生产Secret
Network Policy是否生效
Mount是否只读

可以生成:

public record EnvironmentAttestation(
        String environmentId,
        String imageDigest,
        boolean disposable,
        boolean productionCredentialAbsent,
        String networkPolicyHash,
        String mountPolicyHash) {
}

不满足:

禁止unrestricted

命令本身也要留Hash

command
working_directory
environment
profile

Canonicalize 后算:

command_hash

审批和审计都绑定它。

如果审批后命令变化:

重新审批

一个Execution Ledger

create table agent_execution_ledger (
    execution_id varchar(128) primary key,
    run_id varchar(128) not null,
    profile varchar(64) not null,
    command_hash varchar(64) not null,
    environment_id varchar(128) not null,
    exit_code int,
    outcome varchar(32) not null,
    started_at timestamptz not null,
    completed_at timestamptz
);

以后可以分析:

有多少任务请求过unrestricted
多少真的批准
哪些Agent最频繁

unrestricted使用率应该非常低

指标:

unrestricted_execution_total
/
all_execution_total

如果达到:

20%
30%

说明默认沙箱能力不够,或者团队在滥用 Escape Hatch。

正常应该是极少数。

Escape Hatch要有Expiry

如果某个 Repo 临时允许:

unrestricted

不要永久写配置。

public record ExecutionException(
        String repoId,
        ExecutionProfile profile,
        String reason,
        String approvedBy,
        Instant expiresAt) {
}

到期自动恢复默认。

Sandbox Failure不能自动升级权限

例如命令:

Permission denied

错误行为:

自动加--unrestricted重试

正确:

判断失败原因
↓
生成Permission Upgrade Proposal
↓
重新Policy

很多安全事故就是从:

“为了让测试先跑通”

开始的。

一个Upgrade Proposal

{
  "current_profile": "verify",
  "requested_profile": "unrestricted-verify",
  "failed_command_hash": "sha256:...",
  "reason": "sandbox denied ptrace",
  "environment_attestation": "attest-918"
}

Reviewer 能看清楚为什么需要升级。

验证完成以后环境应该直接销毁

不要把 unrestricted 环境留着:

以后可能还要用

正确:

Create
→Verify
→Extract Artifact
→Destroy

Artifact 只允许:

Patch
Test Result
Trace
Minimal Evidence

不要整个磁盘打包出来。

最少测这10种情况

1. 默认沙箱确实开启
2. --sandbox=false需要显式批准
3. unrestricted只允许Disposable环境
4. 生产Credential存在时禁止升级
5. Network Policy不合格时禁止升级
6. Command Hash变化后审批失效
7. Timeout能杀死进程
8. PID限制能挡住失控进程
9. Sandbox失败不会自动升级
10. 验证完成后环境自动销毁

CodeMender 把沙箱改成默认,是一个非常值得所有 Coding Agent 借鉴的方向。

真正成熟的执行模型应该是:

默认受限
需要时申请升级
升级必须证明环境安全
高权限只存在几分钟
完成后立即销毁

--unrestricted 不应该是“让命令终于跑通”的快捷键。

它应该是一个明确的 Escape Hatch,而且只能在已经足够隔离的验证环境里使用。

当 Agent 可以编译、测试和执行 Shell 后,真正决定安全性的已经不是模型提示词,而是 Runtime 有没有把这种权限升级做成一条可审计、可限时、可撤销的系统流程。


更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界

https://www.zyentor.com/