更新日期:2026-07-25
这一页写给会问「凭什么信你」的人。下面列出我们的信任边界、用到的密码学原语、以及我们明确做不到的事。如果某条你觉得站不住脚,请写信到 security@aidancer.net。
| 角色 | 在哪运行 | 能看到密钥明文吗 |
|---|---|---|
| Vault(钥匙柜) | 你的手机 / 电脑 | 能——这是唯一的明文所在地 |
| Executor(执行器) | 你跑 Agent 的机器 | 仅在一次调用的瞬间,于内存中解出并立刻发出;不落盘 |
| Relay(云端,我们运营) | 我们的服务器 | 不能——只经手密文与元数据 |
| AI Agent | 任意 | 不能——它只写占位符,只收结果 |
你每批准一次,Vault 就用临时 X25519 ECDH + AES-GCM 生成一个只给目标 Executor 的信封。AES-GCM 的 AAD(附加认证数据)绑定:
request_id | template_hash | executor_device_id
因此这个信封换一个 Executor 打不开,换一个请求打不开,模板改一个字节也打不开。信封默认 5 分钟过期,且同一 request 在 Executor 端只允许执行一次(防重放)。
这是整套设计里最关键的一条:Vault 和 Executor 都在本地各自重算 TemplateHash(template),
并用它作为 AAD,绝不信任 Relay 传来的 template_hash 字段。Vault 算的是它实际展示给你看的那份模板——
「你看到的」与「被密码学绑定的」必须是同一份东西,这条链一旦断开,整个绑定就只是摆设。
三端(Go 执行器 / Kotlin 钥匙柜 / Python 云端)的序列化必须逐字节一致,这靠一组共享测试向量钉住: 由 Go 生成,Kotlin 与 Python 各自断言,任何一端改了序列化都会立刻测试变红。
后果:即便我们的云端被完全攻陷、攻击者改写请求模板(比如把你批准的那条 DNS 记录悄悄从
203.0.113.10 改成攻击者的 IP,或者把 target_url 从
api.cloudflare.com 换成他自己的服务器来骗走 token),Executor 端重算出的哈希对不上,
GCM 解密直接失败——密钥根本不会被注入到那个被改写的目标里。这条有回归测试守着
(TestExecutorRejectsTamperedTemplate)。
每个授权信封都带 Vault 设备的 Ed25519 签名。Executor 在首次验证成功时把该 Vault 的签名公钥固定下来(TOFU);
此后同一个 vault device id 换了公钥会被直接拒绝——这是针对「云端偷换设备公钥」的防线。云端也会独立校验一次签名。
默认策略是严格的:没有签名的信封会被拒绝(仅为混合版本车队升级期留了
NODGATE_ALLOW_UNSIGNED_GRANTS=1 这个逃生口,默认关闭)。
device_secret,之后所有 Relay 调用带 X-Device-Id + X-Device-Secret。vault-sync|credential_name|target_device_id,云端只存密文。每把密钥必须声明允许的目标域名;目标越界、或协议不是 https,钥匙柜会直接拒绝并把依据写进审批记录, 授权包根本不会生成。https 是无条件要求,与域名白名单正交——域名对了不代表管道是安全的,且不给回环开口子 (只在本机听的服务,agent 本来就能直连,走审批网关不增加约束)。
在此之上 Executor 还支持可选的出站域名白名单 NODGATE_EXECUTOR_ALLOWED_DOMAINS:即使前面所有环节都被绕过,
密钥也只可能被发往你明确列出的域名。建议生产环境打开。
我们在首页给了一行 curl … | bash,同时也给了「先下载、先校验、再执行」的三行版本和脚本的
SHA-256(首页实时展示,来自服务端对当前文件的计算)。一个卖密钥托管的产品要求你盲管道执行 root 脚本,是自相矛盾的——
所以我们希望你走校验那条路,脚本源码可直接
在浏览器里打开阅读。
目前代码仓库尚未公开。我们计划在独立组织下开源 Executor 与协议实现(Executor 是最需要被审计的一环:它是唯一会碰到明文密钥的自动化组件)。 在那之前,请把本页当作可被逐条质询的承诺清单,而不是既成事实的证明。这一点我们不含糊:尚未开源 = 尚未可验证。
发现问题请发到 security@aidancer.net。我们承诺 72 小时内回复, 不对善意研究者采取法律行动,并在修复后的公告中致谢(除非你要求匿名)。