工作原理

Tokenhush 的工作原理

Tokenhush 是一个本地、仅回环的 HTTP 网关:在机密与 PII 到达模型之前,把它们替换成会话级占位符,并在响应回来时还原。把 AI 编程工具指向本机回环网关,而不是厂商端点:外发方向,整个 JSON 请求体被遍历,每个命中在转发前变成会话级占位符;回程方向,整段响应先被缓冲并解码,占位符再换回原值。

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

一次请求的两个方向

网关位于你的工具与模型提供商之间。请求字节从一个关口出去,响应字节再从这个关口回来,但两个方向并不对称:替换只发生在请求路径上,原值只在响应路径上还原。

一次请求、两条泳道:出站泳道转发出去的请求体里,每个命中都是占位符;入站泳道只在返回你的工具时还原原值。

外发请求

  1. 你的工具发出请求

    工具指向本机回环网关(127.0.0.1:8787),因此请求体会先到达网关,再有任何厂商端点看到它。

  2. 网关遍历并改写请求体

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

  3. 提供商收到改写后的请求体

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

入站响应

  1. 响应先整段缓冲

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

  2. 求值,然后回填

    本次会话铸造的占位符被换回原值;不是本次会话铸造的外部占位符按原样返回。

  3. 你的工具收到响应

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

出站永不回填的设计不变量

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

回填只有一个方向:返回客户端的响应路径。公开核心用一条具名测试钉住它;出站写入方只持有正向映射——它没有反向映射,也没有还原方法。

这条不变量封住一条具体的攻击路径。提示注入可以试图让编码工具把已存储的机密回显进新的外发请求;如果网关在外发方向回填占位符,该请求就会把原值带给模型。由于还原只发生在返回客户端的方向,出现在外发请求体里的占位符依然只是占位符。

  • 这是设计不变量,不是防护保证。 检测是确定性、精度优先的:误报会让模型输出退化,漏报会让内容照常外发。请把本页读作高置信拦截,而不是「任何敏感内容都不会离开」的承诺。
  • 映射只存在于内存,且限定于本次会话。 请求体、响应体、检出的密钥与占位符到机密的映射都不会写入磁盘。重启网关会丢掉映射,占位符可能原样到达你的工具——这是可见的降级,而不是静默失败。
  • 外部占位符按原样返回。 不是本次会话铸造的占位符会按字节原样返回,而不是被猜测成某个机密——不会有任何凭空捏造。

六个检测器类别,五个默认开启

确定性规则运行在外发请求体上;每次命中都会在转发前变成会话级占位符。

检测器集合、默认值与取舍来自公开核心当前版本。
检测器捕获内容取舍
prefix厂商密钥形态——sk-、AKIA、ghp_、glpat-、xox*、AIza、npm_形态列表是有限的:不带已知前缀的凭据留给其他检测器。
jwt按三段式结构识别的 JSON Web Token这是形态规则而不是校验器:只匹配令牌形态,不做签名校验。
pemPEM 私钥头(-----BEGIN … PRIVATE KEY-----)没有 PEM 头到达的私钥不在这条规则的范围内。
luhn通过 Luhn 校验的卡号校验和优先:未通过 Luhn 校验的候选数字串不会被替换。
email以已知公共后缀(.com、.co.uk 等)结尾的邮箱地址按后缀保证精度:域名必须终止于已知公共后缀的标签边界才会命中。
entropy高熵字符串,默认关闭、按工作负载显式开启它在真实 agent 流量上的误报——长工具名与会话 id——破坏了 function calling;而一段合法的 base64 载荷与密钥在构造上无法区分。

在内置规则之外还有两条扩展路径:让指定字面量不被脱敏的允许清单,以及编译期内容插件。签名规则包可以新增检测,而不可弱化下限会拒绝任何削弱内置检测器的包。

响应路径

先整段缓冲,只提交一次

每个上游响应——含 text/event-stream——都在提交任何字节之前完成缓冲与解码。不存在 token 级流式输出,也不存在客户端拿到半截、网关却无法收回的时刻。

  • 缓冲上限超过 response_buffer_bytes(默认 32 MiB)的缓冲响应返回 502,且在提交任何字节之前就已判定。
  • 时限超过 response_timeout(默认 5m)的响应返回 504,同样在提交之前判定;两者同时触发时以缓冲上限为准。
  • 回填最后运行还原是返回客户端路径的最后一步,位于求值之后;外部占位符按原样返回。
提交前的拒绝
502  response over response_buffer_bytes
504  response over response_timeout

设计自带的边界

上面两条路径都带有边界;这些边界写在文档里,而不是留到使用中才发现。

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

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

  • 响应方向不做脱敏

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

  • 不扫描 JSON 的对象键

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

完整边界清单与随之而来的残余风险都记录在安全模型中。

开源

看一次请求如何穿过网关

用 tokenhush run 启动网关,盯着它的 stderr:每次脱敏一行掩码输出,每次还原一次计数,每次本机拒绝给出原因。验证指南会带你走完整个往返。

  • Apache-2.0
  • 不装根证书