上一篇填沙箱坑时,用 sandbox.excludedCommands 把 npm run dev 和 curl 放出了沙箱。那天我接着想让 Claude Desktop 帮我建个 PR,结果一口气又撞了两个沙箱的坑——先是 git push 直接连不上 github,放行之后又遇到 gh 的 TLS 问题。这篇先写前面这个:沙箱的网络出站白名单;后面那个 TLS 坑写在下篇。
想直接拿走结论的话:最快的解法还是老朋友 excludedCommands,加一条 git * 把 git 放出沙箱就完事。下面先讲它,再讲不想一把放开 git 时该怎么按域名收敛地放行。
现象
让 Claude Desktop 走 /create-pr 建 PR,第一步 git push 就挂了:
fatal: unable to access 'https://github.com/lmk123/cvox.git/':
CONNECT tunnel failed, response 403
CONNECT tunnel failed 不是 git 的错、也不是网络断了——是有个代理在中间,对着 github.com 的 CONNECT 请求回了 403。换句话说,请求根本没出去,被就地拦了。
最快的解法:把 git * 放出沙箱
如果你只想赶紧把 git push 跑通,最省事的一招是直接让 git 整个绕开沙箱——在 sandbox.excludedCommands 里加一条 git *:
{
"sandbox": {
"excludedCommands": ["git *"]
}
}
git 在沙箱外跑,自然不受那层出站白名单管,403 当场消失。这招还有几个好处:
- 热重载、即时生效,不用重启会话——即使开了严格沙箱模式、
dangerouslyDisableSandbox被禁用,excludedCommands照样生效; - 顺手把本文末尾那个
.git/config写入失败也一并解决了——那个坑同样是因为 git 在沙箱里跑、.git/config被设了只读,放出沙箱后写 upstream tracking 也不再报错; - git 是跨项目通用的,配在用户级
~/.claude/settings.json一次到位。
代价是放开了所有 git 命令的沙箱限制。 如果你不想给整个 git 开口子、只想精准放行 github 这一个主机,那就继续往下看——用「网络出站白名单」按域名加,是更收敛的办法。
是谁在拦:会话自己起的代理
沙箱里所有命令的网络都被强制走代理,环境变量里写得清清楚楚:
HTTP_PROXY=http://localhost:64310
HTTPS_PROXY=http://localhost:64310
ALL_PROXY=socks5h://localhost:64312
顺手查了下这俩端口是谁在监听:
lsof -nP -iTCP:64310 -sTCP:LISTEN
# claude 66175 mica ... TCP 127.0.0.1:64310 (LISTEN)
监听者就是 claude 进程本身——也就是当前这个 Claude Desktop 会话。所以这代理不是我装的什么网络工具,是会话运行环境自己注入的一层出站过滤:只放行白名单里的主机(api.anthropic.com、中转站、sentry 那几个),github.com 不在名单,于是 403。
这两个端口号每次会话都会变——我后来重启了几次,看到过
64310、也看到过50351。要查当前值得自己env | grep -i proxy。
把我带偏的弯路:改错了配置文件
知道是白名单问题,接下来就是「往哪加 github.com」。我想当然地去翻 Claude Code 的 settings,查到字段是 sandbox.network.allowedDomains,于是在 ~/.claude/settings.json 里加了一段:
{
"sandbox": {
"network": {
"allowedDomains": ["github.com", "*.githubusercontent.com"]
}
}
}
重启会话,再试——还是 403。
这时,我想到我在 Claude Desktop 看到过一个设置项,位置是 Inference configuration -> Workspace restrictions -> Allowed egress hosts。我猜测是 Claude Desktop 用这个设置项覆盖了 settings.json 里的配置。
真正的开关:Allowed egress hosts
Allowed egress hosts(允许的出站主机)的说明文字把它的作用讲得很明白:
Hostnames the agent’s tools may reach from the Cowork and Code tabs. […] When unset, only the inference endpoint is reachable from the sandbox; the agent’s package installs (pip/npm) and web fetches will fail with a 403.
对上了——默认只放行推理(inference)那个端点,其余一律 403,所以连 github、装 npm 包都会挂。这才是真正拦我的那一层。
有个匹配规则的小坑,说明里特意点了出来:
Wildcards don’t cross schemes.
*.corp.commatchesdocs.corp.combut notcorp.comitself; add both if you need the apex.
通配符只匹配一级子域,不含顶级域本身。 所以不能只写 *.github.com 就完事——github.com 这个 apex 它不匹配,而 git push 走的恰恰是 apex。我加了这三条:
github.com
*.github.com
*.githubusercontent.com
github.com(apex)——git push直连它,必须;*.github.com——覆盖api.github.com(gh 建 PR 用)、codeload.github.com等;*.githubusercontent.com——release 资源 / LFS 下载之类。
设置里还有个
* Allow all的选项,能一把放开所有出站。但那等于把这层过滤整个关掉,比需要的宽太多——加具体主机就够,没必要图省事。
改完重启 Claude Desktop,再 git ls-remote 测一下:
git ls-remote origin HEAD
# 24472e63... HEAD ← 通了
git push -u origin <branch>
# * [new branch] ... ← push 成功
github 终于连上了。
一个小尾巴:push 成功但报 config 写入失败
push 那一下还顺带飘了两行红字:
error: could not write config file .git/config: Operation not permitted
看着吓人,其实无伤大雅。这是 git push -u 想往 .git/config 写 upstream tracking,被沙箱的文件写权限挡了——跟网络白名单是两码事。分支已经推上去了,tracking 也设上了,这行只是个没写成的副作用,忽略即可。
顺带一提:如果你走的是开头那条 git * 放出沙箱的路子,这个 config 写入失败也一并没了——git 不在沙箱里跑,.git/config 自然能写。这正是「一把放开 git」比「按域名加白名单」省心的地方:网络和文件写两层坑一次绕开。
收尾,以及那个 TLS 坑
github 一通,git push 就过了。然而 gh pr create 立刻又撞上 TLS 那道墙——那是另一层、另一个故事,留到下篇写。
两个坑摞在一起,回头看是两层独立的过滤,得分开治:
- 网络出站白名单(这篇):管「能不能连到这个主机」。图快就
excludedCommands加git *把 git 整个放出沙箱(连带解决 config 写入失败);想收敛就 Allowed egress hosts 按域名加。 - Seatbelt 沙箱 + trustd(下篇):管「Go CLI 能不能验证 TLS 证书」,治法是
excludedCommands把gh放出沙箱。