给 agent 配 API key 这件事,我一直是硬着头皮做的。
key 落在配置文件里,agent 手上有 shell。它能读的文件我拦不住,更麻烦的是它跑起来的那些东西:一段临时脚本、一个刚装上的插件、一条随手的 curl,全在同一个进程环境里,那串 sk- 开头的字符对它们都是敞开的。出事的前提不需要模型学坏,只需要有人往对话里塞一句话。
OpenClaw 新出的这个预发布版给的解法我没想到:agent 环境里那串 key 是假的。
版本号 v2026.8.1-beta.2,从上一个 beta 到它有两千六百多个提交。我把它装进一个隔离目录,状态和配置都指到临时路径,跑了一遍下面这些命令,输出都是原样贴的。
agent 拿到的是一张兑换券
这版新加了一个团队级的密钥仓库。我本机跑的还是 7 月那版,它的 secrets 底下只有四个命令,没有 store 这一层,敲 secrets store 它给我打的是 secrets 自己的帮助:
| $ openclaw secrets --help # 我本机在跑的 2026.7.1-2 Commands: apply Apply a previously generated secrets plan audit Audit plaintext secrets, unresolved refs, and precedence drift configure Interactive secrets helper reload Re-resolve secret references and atomically swap runtime snapshot |
新版把它扩成了一个带 set / list / get / rm / import 的库。真正有意思的是密钥交到 agent 手上之前那一步:存进去的值不会原样进子进程,进去的是这么一串东西。
| oc-sent-v2.<一长串 base64url>.end |
这是 AES-256-GCM 封出来的密文,封它的密钥是网关进程启动时随机生成的 64 字节,不落盘。所以这串东西离开这个进程就没有意义,网关重启一次,旧的也解不开。真值只在请求离开进程的前一刻被换回去,URL、请求头、请求体都换。碰到认不出来的密文,它选择拒发,不会把没解开的东西丢给对端。
说白了就是给 agent 一张兑换券。券只在开票的那台机器上有效,兑换发生在最后一步。
它文档里有句话我觉得值得抄下来:这不算进程隔离。真值仍然在同一个进程的内存里,最后那个适配器边界上一定会出现明文。一个安全功能肯把自己的天花板写出来,我愿意多信它一点。
这张券只认一个域名
密文只解决了「看不见」,没解决「能发到哪」。这版补的那半是:每个密钥必须自己声明允许出网的域名,逐字匹配。
| $ echo -n "sk-xxxx" | openclaw secrets store set DEEPSEEK_API_KEY --kind secret Stored DEEPSEEK_API_KEY (secret). $ openclaw secrets store set DEEPSEEK_API_KEY --allow-host *.deepseek.com Allowed host "*.deepseek.com" cannot contain a wildcard; use one exact hostname. $ openclaw secrets store set DEEPSEEK_API_KEY --allow-host https://api.deepseek.com/v1 Allowed host "https://api.deepseek.com/v1" must be a hostname without a scheme, path, wildcard, or port. $ openclaw secrets store set DEEPSEEK_API_KEY --allow-host API.DeepSeek.com Allowed DEEPSEEK_API_KEY for api.deepseek.com. $ openclaw secrets store list DEEPSEEK_API_KEY [secret] (write-only); allowed hosts: api.deepseek.com |
通配符不认,带 scheme 或路径不认,端口也不认。大写自己折成小写,国际域名折成 punycode。一个密钥最多绑 128 个域名,这个上限写在源码里。
没绑域名的密钥是彻底用不了的状态,不是宽松放过。
发到没绑的域名会被拒,报错顺手把该敲的命令打出来:
| Secret "DEEPSEEK_API_KEY" is not allowed for host "example.com". Run: openclaw secrets store set DEEPSEEK_API_KEY --allow-host example.com |
还有两个小设计我挺喜欢。secret 类型的值存进去就读不出来,store get 直接拒;--value 参数也被拒,理由是命令行参数会进 shell 历史和进程列表。这两条我都试了。
| $ openclaw secrets store set DEEPSEEK_API_KEY --kind secret --value sk-xxxx --value is refused for secret entries. Use a stdin pipe, --value-file, or the interactive no-echo prompt. $ openclaw secrets store get DEEPSEEK_API_KEY Secret store entry "DEEPSEEK_API_KEY" is write-only by design. Reference it from config with a store SecretRef. |
同一把 key 的两条走法:以前是明文进环境,这版是密文进环境、出网前按域名换回真值
打开之后,agent 的网络长什么样
这套东西默认是关的。我在隔离目录里查了一下,配置里根本没这一项:
| $ openclaw config get secrets.egressProxy Config path not found: secrets.egressProxy. Run openclaw config validate to inspect config shape. $ openclaw config set secrets.egressProxy.enabled true --strict-json Updated secrets.egressProxy.enabled. Restart the gateway to apply. |
开起来之后,网关会往它托管的 exec 环境里塞几样东西:两个代理变量指向本机回环上的代理,URL 里带一次性口令;四个证书变量指向临时 CA;还有每个密钥对应的那串密文。
代理走标准 Basic 认证,用户名固定,口令每次运行随机生成,一次运行结束就作废,认证不过给 407。临时 CA 每次网关启动生成一份,目录 0700、私钥 0600,网关关掉就删,从不装进系统信任库。
请求体是流式扫的,带一个滑动窗口,所以密钥被切在两个数据块中间也能拼回来替换,往接口传一个大文件、密钥夹在中间那种情况也算。
有证书固定需求的客户端可以列进 bypassHosts,那条路走盲隧道,里面不做任何替换。发进去的是密文,厂商只会认为凭据无效然后拒掉,反而是安全的。
它挡不住什么,官方自己列了
安全功能的边界比功能本身重要。这几条我照文档和源码核过,挑影响判断的:
团队仓库是明文存的。值躺在状态目录的 SQLite 里,没有加密,靠 0600 / 0700 的文件权限撑着。要更硬的隔离得挂外部凭据服务。
只覆盖网关自己托管的 exec。沙箱里的 exec 和远程节点上的 exec 既拿不到代理变量也拿不到密文;外部编码 agent 的 harness 自己拼子进程环境,这条路上根本不经过它。以为整台机器都被保护了,实际只保护了一条路,这是我觉得最容易误判的一条。
绑了域名不等于那个域名可信。被绑的服务要是把请求里的凭据回显出来,明文照样回到 agent 手里。DNS 被改也能绕,因为策略绑的是主机名不是 IP。
协议上有硬缺口。上游 HTTP/2 不支持,WebSocket 不改写,非 443 端口不支持,纯 HTTP 直接拒,不升级也不替换。
后台常驻进程会突然失去授权。它所属的那次运行一结束,进程还活着,但请求过不去了。长跑脚本会莫名断在半路。
所以我不会马上把它开到主力网关上,HTTP/2 那条现在就能踩到人。但把仓库建起来、把域名绑上,这两步不影响现在的用法,我先做了,等进正式版直接开。
这机制真正值钱的地方,是把「我的 key 有几条路能出去」变成了一张列得出来的清单。以前这个问题我答不上来。
这版另外几件事
剩下的我按扫 changelog 的顺序挑了几条对日常有感知的,其他大半是内部重构。
该版本其余几条改动,来自 changelog 的 Highlights 与 Changes
备份那条我顺手试了命令,确实在,恢复只允许写到一个新库,不给你机会直接盖掉正在用的那个:
| $ openclaw backup sqlite --help Commands: create Create a compact, verified snapshot of an OpenClaw SQLite database list List committed snapshots in a repository restore Restore a verified snapshot to a new SQLite database path verify Verify a snapshot manifest, artifact hash, SQLite integrity, and database owner |
插件那条跟前面是一条线上的事。在聊天窗口里让它装插件,现在只认可信目录,别的可执行来源要你自己回到信得过的 shell 里加 --force。源码里那句提示写得很直白:只装 ClawHub、内置和官方目录里的插件,任意可执行来源你自己去审。
你那把 key 有几条路能出去
如果你手上也有个能跑 shell 的 agent,可以先做一件不花时间的事:把现在能读到那把 key 的进程列一遍。列不出来,就正好是这版想解决的问题。
真要现在就动手,三条命令够了,前两条不影响你现在的用法:
| echo -n "$KEY" | openclaw secrets store set DEEPSEEK_API_KEY --kind secret openclaw secrets store set DEEPSEEK_API_KEY --allow-host api.deepseek.com openclaw config set secrets.egressProxy.enabled true --strict-json && openclaw gateway restart |
这篇里的所有输出,来自 v2026.8.1-beta.2 的一份隔离安装,文档和源码引用都来自同一个 tag。
你那把 key,现在有几条路能出去?评论区说说你数出来几个。
夜雨聆风