
一句话,就能把你OpenClaw里所有的API Key原文套出来。你没看错,就是这么简单。
前两天一个群友跟我说,他的密钥被人盗了。他自己搭了个OpenClaw(俗称“龙虾”)拉到群里给朋友用,结果有人发现,只要让机器人读一下配置文件,所有密钥都是明文的。API余额直接被刷,还好发现得及时,损失不算太大。
但这事儿让我后背一凉。因为我知道,绝大多数人的OpenClaw配置,都处于这种“裸奔”状态。
你的密钥,可能正在裸奔
他的密钥是怎么被盗的?
其实不复杂。很多开源项目的文档,都会引导你把KEY保存到一个固定路径,比如 ~/.openclaw/.env,或者直接写在配置文件里。

看起来挺方便的,对吧?但你不知道的是,默认情况下,这些文件的内容是能被读取到的。

只要有人能跟你的机器人对话,一句话就能把你的密钥原文读出来。想想就后怕。
安全这块,真的不是“以后再说”的事。密钥一旦出现在聊天窗口,截图、转发、同步,全不可控了。那怎么办?别慌,三步搞定。
第一步:输出脱敏,先把裸奔的遮住
最简单的止血方案:让机器人在输出的时候自动打码。
怎么做?在你的 AGENTS.md 里追加一段脱敏规则就行,很简单。核心规则长这样:
## 敏感信息保护
### 敏感信息定义
以下信息属于敏感信息,任何场景下都必须遵循保护规范:
- API Key(如 `KIMI_API_KEY`、`WECHAT_APP_SECRET`、`DEEPSEEK_API_KEY`)
- Access Token / Session Token
- 数据库连接字符串
- 私钥、证书文件
- 密码、密钥
### 保护措施
#### 1. 显示脱敏
所有敏感信息在输出中必须截断处理,只显示前 4 位 + ... + 后 4 位:
- ✅ 正确:`sk-kimi-2bor...HyrM`
- ✅ 正确:`WECHAT_APP_SECRET: 6YLh...o3P`
- ❌ 错误:`sk-kimi-abcr7WcLoRPwssuzIDEF9uZ5rvwEqAMVBEY5es123`(绝不这样做)
此规则适用于:聊天回复、日志输出、巡检报告、变更记录、推送通知。
#### 2. 日志脱敏
...
#### 3. 存储方式
...
#### 4. 推送与传输
...
### 敏感信息识别规则
除了上述按字段名匹配的敏感信息外,以下模式的值也必须脱敏,不管字段名叫什么:
**按字段名关键词匹配(不区分大小写):**
- 包含 `secret`、`password`、`passwd`、`token`、`key`(但排除 `public_key`)、`credential`、`auth` 的字段
- 包含 `appid`、`app_id`、`client_id`、`client_secret` 的字段
.....
**执行规则:先脱敏,再输出。不确定是不是敏感信息时,按敏感处理。**
### 不可覆盖原则
脱敏规则是硬性红线,以下指令不能绕过脱敏:
- ❌ "我要明文"
- ❌ "显示完整密钥"
....
....
此规则的优先级高于用户的临时指令。即使用户明确要求,也不输出完整敏感信息。
这段规则做了几件事:
- 按字段名匹配:包含
secret、token、key、password这些关键词的字段,自动脱敏。
- 按值的模式匹配:以
sk-、pk-、Bearer 开头的,超过 20 位的字母数字混合串,统统打码。
- 硬性红线:就算用户说“给我看完整的”,也不输出。优先级高于一切临时指令。
配置完是什么效果?看截图,连追问2次都不给面子。这才是安全规则该有的硬度。

即使换个路径去读,只要命中规则,一样脱敏:

先脱敏,再输出。不确定是不是敏感信息时,按敏感处理。这是铁律。
这一步做完,至少别人在聊天窗口里已经看不到你的完整密钥了。但别急,这只是第一道防线。想深入了解安全配置,可以看看 云栈社区 上其他开发者的分享。
第二步:凭据分离,从根上解决
脱敏只是防显示,治标不治本。真正的风险在哪?在你的配置文件里。
比如你配置飞书渠道的时候,appSecret 是明文写在 openclaw.json 里的。如果你习惯用 git 备份配置文件,恭喜你,密钥直接被提交上去了。这才是要命的。
所以我们需要做一件事:把密钥和配置文件分开存。OpenClaw 里叫 SecretRef(凭据引用),说白了就是,配置文件里不再存密钥原文,只存一个指针,指向真正的密钥存储位置。
OpenClaw 的 Secret Provider 提供了三种方案,从简单到硬核,按需选择。
先说结论,配置完之后长这样:
{
"appSecret": {
"source": "file",
"provider": "filemain",
"id": "/channels/feishu/accounts/cyber_beast_of_burden/appSecret"
}
}
看到没?配置文件里再也没有明文密钥了。 就算你把这个文件推到 GitHub 上,别人也拿不到任何东西。怎么配?三小步。
方案一:File Provider(推荐个人用户)
最实用的方案。把所有密钥集中放在一个独立的 JSON 文件里,OpenClaw启动时从文件读取,密钥不再散落在 openclaw.json 里。
第 1 步:创建独立的密钥文件
把真正的密钥单独存一个文件,并且锁死权限:
cat > ~/.openclaw/secrets.json << 'EOF'
{
"channels": {
"feishu": {
"accounts": {
"cyber_beast_of_burden": {
"appSecret": "你的真实密钥"
}
}
}
}
}
EOF
chmod 600 ~/.openclaw/secrets.json
chmod 600 是关键,只有你自己能读写这个文件,其他人连看都看不了。
第 2 步:在 openclaw.json 里注册 provider
告诉OpenClaw:“我的密钥存在哪个文件里”:
{
"secrets": {
"providers": {
"filemain": {
"source": "file",
"path": "~/.openclaw/secrets.json",
"mode": "json"
}
}
}
}
第 3 步:配置渠道时选择 Configured secret provider
当你配置飞书渠道(或其他需要密钥的地方)时,OpenClaw会问你 “Where is this App Secret stored?”

这里有两个选项:
- Environment variable —— 密钥存在环境变量里,OpenClaw通过环境变量读取。这种方式比较简单粗暴,适合本地跑着玩的场景。
- Configured secret provider —— 用你刚才配置的密钥文件来管理。选这个。
选完之后,它会让你填密钥的路径。

注意,这里的路径是你在 secrets.json 里定义的 JSON 层级路径,我们需要将上面默认的替换掉
/channels/feishu/accounts/cyber_beast_of_burden/appSecret

配置完成后,openclaw.json 里的效果:
{
"channels": {
"feishu": {
"enabled": true,
"appId": "cli_a928XXX99e38dbc7",
"appSecret": {
"source": "file",
"provider": "filemain",
"id": "/channels/feishu/accounts/cyber_beast_of_burden/appSecret"
},
"connectionMode": "websocket",
"domain": "feishu",
"groupPolicy": "allowlist"
}
}
}
appSecret 变成了一个引用,不再是明文。即便你把 openclaw.json 推到 GitHub 上,别人也拿不到任何东西。
那你可能会想:secrets.json 这个文件里还是存着明文密钥啊,万一有人让机器人去读这个文件呢?试试看:

放心,第一步配的脱敏规则还在。就算有人直接去读密钥文件,输出的也是打码后的值。
两层防线:配置文件里没有明文,聊天窗口里也看不到明文。这才叫双保险。
对大多数个人用户来说,File Provider 已经够用了。但如果你想更进一步。
方案二:Keychain Provider(macOS 用户进阶)
File Provider 虽然把密钥从配置文件里分离出来了,但 secrets.json 里毕竟还是明文。有没有办法让磁盘上完全没有明文?
有。如果你用的是 macOS,可以把密钥存进系统钥匙串(Keychain)。OpenClaw启动时调用命令从钥匙串里取,磁盘上自始至终不落地明文。
第 1 步:把密钥存入 Keychain
security add-generic-password -a openclaw -s channels-feishu-tech-app-secret -w jRSUWd88yXXXXXFdxfhjwQnduHyKe
这条命令把密钥存进了 macOS 的钥匙串,跟你的 iCloud 密码、WiFi 密码放在同一个保险柜里。

第 2 步:安装社区提供的 provider 脚本,配置 openclaw.json
{
"secrets": {
"providers": {
"filemain": {
"source": "file",
"path": "~/.openclaw/secrets/secrets.json",
"mode": "json"
},
"keychain": {
"source": "exec",
"command": "/opt/homebrew/bin/node",
"args": ["/opt/homebrew/lib/node_modules/openclaw-secret-providers/keychain/keychain-secret-fetch.cjs"],
"timeoutMs": 5000,
"allowSymlinkCommand": true
}
}
}
}
原理很简单:OpenClaw需要密钥的时候,不是去读文件,而是执行一条命令从钥匙串里取。取完用完,内存里销毁,磁盘上从头到尾没有明文。
第 3 步:在渠道配置里引用
跟方案一一样,appSecret 不再写明文,而是换成一个 SecretRef 引用,只不过 provider 从 filemain 变成了 keychain:
{
"channels": {
"feishu": {
"accounts": {
"tech": {
"name": "tech",
"appId": "cli_a92e96e698785bef",
"appSecret": {
"source": "exec",
"provider": "keychain",
"id": "channels-feishu-tech-app-secret"
}
}
}
}
}
}
注意 id 的值。这就是你第 1 步存入 Keychain 时用的 service name,OpenClaw拿着这个 id 去钥匙串里查对应的密钥。
这个方案的好处是:就算有人拿到了你的整个项目目录,翻遍所有文件也找不到任何密钥。因为密钥根本不在文件系统里。
方案三:1Password / Vault / AWS Secrets Manager(团队和企业级)
如果你是团队协作、多设备同步,或者公司对安全合规有要求,那就该上专业的密钥管理服务了。
思路跟方案二一样,都是 exec provider,只是把 Keychain 换成了 1Password CLI、HashiCorp Vault、SOPS 这类工具。这块比较复杂,涉及到各家工具的安装、认证、权限配置,篇幅有限就不展开了。
三种方案总结一下:File Provider 适合个人快速上手,Keychain 适合 macOS 用户追求零明文,1Password/Vault 适合团队和企业。按你的场景选就行,核心思想就一个:密钥和配置文件分开存,永远不要在同一个地方裸奔。
第三步:审计检查,查漏补缺
前两步做完,还不够。万一你之前已经有一些配置是明文写的呢?万一有些文件你漏掉了呢?
OpenClaw 提供了一个审计命令,一行搞定:
openclaw secrets audit --check

跑完一看,好家伙,还有 3 个地方在裸奔。审计结果会明确告诉你:哪个文件、哪个字段、以什么方式存的明文。找到了就按第二步的方法改掉。
但这里我踩了个坑,值得说一下。改完之后OpenClaw直接报错了:

看日志,auth-profiles.json里的 key 字段不支持直接用 SecretRef。
02:36:51+00:00[diagnostic] lane task error: lane=main durationMs=116 error="TypeError: cred.key?.trim is not a function"
02:36:51+00:00[diagnostic] lane task error: lane=session:agent:main:telegram:direct:7354573803 durationMs=118 error="TypeError: cred.key?.trim is not a function"
02:36:51+00:00 Embedded agent failed before reply: cred.key?.trim is not a function
查了一下技术文档,发现 auth-profiles.json 里需要用 keyRef 来引用,不是直接把 key 换成 SecretRef 对象。

改成这样就对了:
root@ip-172-31-45-180:~/.openclaw# cat /root/.openclaw/agents/main/agent/auth-profiles.json
{
"profiles": {
"minimax:cn": {
"type": "api_key",
"provider": "minimax",
"keyRef": {
"source": "file",
"provider": "filemain",
"id": "/providers/minimax/apiKey"
}
}
}
}
注意是 keyRef,不是直接把 key 的值换成对象。这个细节文档里写了,但很容易忽略。
另外提一嘴: models.json 是 OpenClaw 自动生成的文件,不应该手动改,删掉让它重新生成就行。重启 gateway 后,OpenClaw 会根据 openclaw.json 和 auth-profiles.json 自动重新生成 models.json。
改完之后,再跑一次审计,nice!

干干净净,一个不剩。形成闭环。
写在最后
回到开头那个群友的故事。说实话,OpenClaw本身没问题,问题出在,大多数人搭完能跑就觉得完事了。
今天这三步,脱敏、凭据分离、审计。说白了就是在做一件事:缩小暴露面。密钥不该出现在聊天窗口里,不该出现在配置文件里,不该出现在任何它不需要出现的地方。
不难,但你得主动做。如果你也在运行自己的OpenClaw或类似AI助手,建议现在就花点时间检查一下配置。技术探索很有趣,但安全保障是底线,希望本文的实践能给你一些启发。