脱敏密钥

在机密到达模型之前完成脱敏

Tokenhush 是一个本地、仅回环的 HTTP 网关:位于 AI 编程工具与模型提供商之间。外发方向,它遍历声明为 JSON 的请求体,把检测到的密钥或 PII 替换成可还原的会话级占位符,再转发改写后的请求体;回程方向,它先整段缓冲响应,并在你的工具收到之前还原原值。想在发送给 LLM 之前脱敏密钥、又不想在机器上信任一张全局证书时,这就是可用的检查点。

仅绑定本机回环、不做 MITM、不装根证书;密钥与占位符的映射仅保留在内存中,限定于本次会话。

问题:密钥与 PII 同时外发

AI 编程工具用仓库上下文组织请求。.env 文件里的密钥、配置文件里的令牌、粘贴进提示词的凭据,对工具来说都不是特例:它们只是文本,会随请求体一起发出。

文件级卫生在请求形成之前就已经生效:.gitignore 让文件不进 git,厂商开关减少服务端保留的内容——但两者都不在发送时运行,而请求一旦发出就无法撤回。发送时脱敏是另一个检查点:请求体在工具组织完成之后、提供商收到之前被改写。回环网关就位于这个位置,这也是它与对比页里其他做法在脱敏视角上的关键区别。

面向 LLM 请求的 PII 脱敏同理:通过 Luhn 校验的卡号、以已知公共后缀结尾的地址,会被同一次确定性遍历命中并替换为占位符,提供商收到的是请求的形态,而不是具体的值。

外发脱敏,回程还原

把工具指向本机回环网关(127.0.0.1:8787),而不是厂商端点。一次请求、两个方向,只有其中一个方向会改写:替换发生在请求路径上,原值只在响应路径上还原。

外发请求

  1. 工具把请求指向本机回环

    请求体先到达网关,再有任何厂商端点看到它。这里没有流量拦截:工具被配置为直接访问回环地址。

  2. 网关遍历请求体并写入占位符

    完整读取声明为 JSON 的请求体,运行已启用的检测器;每个命中变成会话级占位符,例如__PII_api_key_ae9c0b46a8f3__,改写发生在转发之前。

  3. 提供商收到占位符而不是原值

    上游看到的是占位符,而不是它们所代表的值。没有被任何检测器标记的值仍按工具写下的原样发出——这正是检测器质量构成工具诚实边界的原因。

入站响应

  1. 响应先整段缓冲

    先记录状态码与响应头,再把响应体(含 text/event-stream)完整缓冲并解码;此时还没有提交任何字节。

  2. 占位符回填为原值

    本次会话铸造的占位符被换回原值;不是本次会话铸造的外部占位符按原样返回,而不是被猜测成某个机密。

  3. 原值回到工具

    回填最后运行,响应一次提交,因此客户端不会拿到半截、网关却无法收回的响应。

占位符在出站方向永不回填。只有客户端拿到原值。

回填只有一个方向:返回客户端的响应路径。出站写入方只持有正向映射——没有反向映射,也没有还原方法——因此出现在新的外发请求体里的占位符依然只是占位符。

脱敏对照:四种做法

下面每种做法都能减少离开机器的内容;区别在于减少发生在什么时刻,以及仍带着密钥的请求会经过哪里。

取自公开核心 README 的四种做法,按脱敏视角展开;mitmproxy 作为本机代理这一类的公开示例被点名。
做法对请求中的密钥做什么运行位置
依赖 .gitignore 与厂商开关发送时不运行任何检查:记得排除的文件不进 git,忘了排除的文件里的密钥照样随请求外发。文件级卫生,在请求被组织出来之前生效。
关掉发送过多的功能离开机器的字节更少,但对已经进入请求体的密钥无能为力。厂商侧设置,按提供商生效,而不是按请求生效。
带根证书的本机 MITM 代理机器上任何客户端都能被检查与改写,包括没有 base URL 设置的客户端;它要终止 TLS,于是根证书要在全机器范围被信任。系统级:位于每个客户端与每个端点之间。
Tokenhush声明为 JSON 的请求体被遍历,每个命中在转发前变成会话级占位符;不终止 TLS、不装根证书,映射只保留在内存中。仅本机回环:在你能指向 base URL 的那些工具的请求路径上,只有一个检查点。

检测器偏向精度:未被任何检测器标记的值仍会外发。公开口径是高置信拦截加全程可审计,而不是「什么都不会外泄」的保证。

脱敏不做哪些事

在机密到达模型之前完成脱敏,不等于「防止一切形式的机密外泄」。这些边界随设计而来,写在文档里,而不是留到使用中才发现。

  • 编码后的密钥不会被捕获

    外发前经过 base64、hex 或 URL 编码的密钥不会被检测到:改写过程没有归一化环节。JSON 字符串转义在两个方向都被处理;非 identity 的请求 Content-Encoding 会以 415 拒绝,而不是解码后再检测。

  • 响应方向不做脱敏

    响应侧规则只能 allow、warn 或 block;替换只属于请求路径,任何试图对响应脱敏的规则在编译时即被拒绝。

  • 不扫描 JSON 的对象键

    只遍历值,因此把密钥用作对象键时会原样转发。

完整边界清单与随之而来的残余风险都记录在安全模型中。覆盖范围恰好是你能指向 base URL 的工具;无视 base URL 的客户端需要另一套拦截设计。

本机验证

用本地 echo 上游验证脱敏

验证指南用本地 echo 上游证明整个往返:上游把收到的请求体原样回显。上游终端显示的是占位符;网关的 stderr 每次脱敏打印一行掩码输出、每次还原打印一次计数;客户端拿回原值。

  • 上游看不到原值echo 上游就是模型的替身:它打印收到的请求体——那是占位符,不是密钥。
  • 日志只含元数据脱敏行只有类型、长度与掩码形态;还原行只有计数。
  • 元数据可查询tokenhush status --json 会报告 redactions 这类计数,机器可以复核人刚看过的同一次往返。
把工具指向本机回环网关
tokenhush run
# point a tool at http://127.0.0.1:8787
tokenhush status --json

开源

把一个工具指向网关

从验证指南开始:本地 echo 上游、一条携带假密钥的请求,以及一份显示上游到底收到了什么的日志。然后按你使用的工具查看接入配置。

  • Apache-2.0
  • 不装根证书