面向 AI 编程工具的本机回环网关

在请求抵达模型之前,于本地完成密钥与 PII 脱敏

Tokenhush 位于 AI 编程工具与厂商 API 之间:它把外发请求体中检测到的密钥替换为会话级占位符,转发清洗后的请求,并在响应中还原原文——你的工具照常拿到真实值。

核心以 Apache-2.0 开源。不做 MITM、不装根证书;密钥与占位符的映射仅保留在内存中。

5
个默认开启的检测器
14
个自带现成配置片段的工具
7
个 CLI 命令,不多不少
Apache-2.0
开源许可证

每个数字都可以对照公开核心核验;全部数字的来源均已登记在站点的内容来源映射中。

你的工具发出
OPENAI_API_KEY=<real key>
模型收到
OPENAI_API_KEY=__PII_api_key_ae9c0b46a8f3__
你的工具拿回
OPENAI_API_KEY=<real key>

占位符形态__PII_<type>_<digest>__

网关在转发前遍历整个请求体;占位符按会话生成,密钥到占位符的映射在重启后即被丢弃。

网关做什么

在工具前面设一道检查点:读取每个请求,替换看起来像密钥的内容,再转发清洗后的请求体。

  • 逐层遍历每个嵌套字段

    完整读取外发 JSON 请求体,因此藏在嵌套对象与数组里的密钥同样会被识别,而不只是顶层字段。响应(含 SSE 流)会先整体缓冲,再提交任何字节。

  • 六个内置检测器,五个默认开启

    prefix、jwt、pem、luhn、email 默认开启;第六个 entropy 按工作负载自行选择,因为它在真实 agent 流量上的误报会破坏工具调用。

  • 可还原、会话级占位符

    命中内容会变成 __PII_api_key_ae9c0b46a8f3__ 这样的占位符。密钥与占位符的映射只在本次会话的内存中保留,重启网关即丢弃。

  • 仅回环,且带多重校验

    绑定 127.0.0.1;主机存在 IPv6 回环时同时绑定 [::1]。Host 白名单始终校验,浏览器式请求会校验 Origin,控制接口位于每次运行生成、权限为 0600 的令牌之后。

  • 签名规则包,且不可削弱内置

    tokenhush rules sync 在使用前校验 Ed25519 签名、新鲜度与序列号;若规则包禁用内置检测器、丢掉必需类别或携带 allow 动作,防线会直接拒绝。

  • 小、可移植、可扩展

    纯 Go,以 CGO_ENABLED=0 构建。扩展按设计在编译期完成:内置检测器、签名规则包与第三方规则都通过同一份 Rule 契约进入同一注册表。

Tokenhush 不做什么

边界是设计的一部分,每条都写在文档里,而不是留到使用中才发现。

  • 不做 MITM,不装根证书

    Tokenhush 从不终止 TLS。这也意味着 Cursor agent 流量、ChatGPT 与 Claude 桌面应用、浏览器 Web UI 不在覆盖范围内:它们不认可配置的 base URL。

  • 响应方向不做脱敏

    响应侧规则只能 allow、warn 或 block。超过缓冲上限的响应是 502,超过超时的响应是 504,两者都发生在提交任何字节之前。

  • 编码后的密钥不会被识别

    外发前经过 base64、hex 或 URL 编码的密钥不会被检测到;非 identity 的 Content-Encoding 会以 415 拒绝,而不是解码后再检测。

  • 不扫描 JSON 的对象键

    只遍历值;因此把密钥用作对象键的情形不会被捕获。

  • 扩展只在编译期

    没有运行时插件加载、没有 allowlist 变更端点、也没有内置的常驻服务命令——想让网关随登录启动,请交给操作系统自带的服务管理器。

完整边界清单与随之而来的残余风险都记录在文档中。

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

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

检测器集合与默认值取自公开核心当前版本。
检测器捕获内容默认状态
prefix厂商密钥形态——sk-、AKIA、ghp_、glpat-、xox*、AIza、npm_开启
jwtJSON Web Token开启
pemPEM 私钥头(-----BEGIN … PRIVATE KEY-----)开启
luhn可通过 Luhn 校验的卡号开启
email域名为已知公共后缀(.com、.co.uk 等)的邮箱地址开启
entropy高熵字符串——默认关闭,因为它在真实 agent 流量上的误报会破坏工具调用关闭(按需开启)

十四个工具,各一条配置片段

任何支持自定义 base URL 的客户端都能接入。以下 14 个工具自带 tokenhush env 生成的现成片段;Anthropic 风格客户端填裸 origin,OpenAI 兼容客户端填 /v1。

用别的客户端?把它的 OpenAI 兼容 base URL 指向 http://127.0.0.1:8787/v1,或把 Anthropic base URL 指向 http://127.0.0.1:8787。

Tokenhush 与其他做法对比

四种常见做法,以及各自放弃的东西。

做法带来什么不带来什么
依赖 .gitignore 与厂商开关不需要额外软件:把密钥挡在你记得排除的文件之外,并按工具关闭厂商侧特性。你得把每个模式都配对并一直维持;只要漏掉一个 .env,内容照样离开机器,而请求发出后无法撤回。
关掉发送过多的功能离开机器的字节更少,有时少很多。能力被削弱,设置可能漂移或被更新重置,也完全挡不住仍然进入请求的密钥。
带根证书的本机 MITM 代理可以检查和改写机器上任何客户端的流量,包括没有 base URL 设置的客户端。它要终止 TLS,于是你得安装根证书,并在机器上永久信任一个第三方。
Tokenhush你的工具指向的本机回环网关:请求体中是可还原的占位符,在响应中还原。不终止 TLS、不装根证书,映射只保留在内存中。只覆盖能把工具指向 base URL 的场景(自带 14 个工具片段)。响应方向不做脱敏,不识别编码后的密钥,也不覆盖无视 base URL 的客户端。

01本机优先

仅回环,不装根证书

Tokenhush 绑定 127.0.0.1,主机存在 IPv6 回环时另绑 [::1],并对每个请求校验 Host 白名单。它从不终止 TLS,因此不需要根证书,也不做系统级拦截。

  • 没有需要系统级信任的东西没有根证书、不终止 TLS,控制面也只有唯一接口:带每次运行令牌的 GET /status。
  • 两种 base URL 形态Anthropic 风格客户端填裸 origin;OpenAI 兼容客户端填 /v1。
网关 base URL
# Anthropic 风格客户端
http://127.0.0.1:8787

# OpenAI 兼容客户端
http://127.0.0.1:8787/v1

02失败行为

失败时收紧,而不是放开

检测器出错时请求会被拒绝,而不是未经脱敏就转发。编码、体积与时限各自都有明确的拒绝方式,不会静默地发出半成品。

  • 没有部分转发超过内存守卫的请求体在任何上游连接之前即被拒绝;超过缓冲上限的响应在提交前返回 502。
  • 不猜编码非 identity 的 Content-Encoding 直接以 415 拒绝,而不是解码后再检测。
提交前的拒绝
403  body_too_large
415  unsupported Content-Encoding
502  response over the buffer cap
504  response past the timeout

03扩展方式

在编译期扩展

内置检测器、签名规则包与你自己的 Go 包,都通过 pkg/filter 的 Rule 契约进入同一注册表,并按同一确定性顺序求值。

  • 只做加法,不做减法签名规则包可以新增检测、扩展内置 email 后缀集合;任何削弱内置的行为都会被防线拒绝。
  • 一个注册表内置检测器、规则包与第三方规则共用同一注册表与同一求值顺序。
三条路径,一个注册表
built-ins            →  one registry
signed rule packs    →  verified, non-weakening floor
compile-time plugins →  your own Go package

什么会离开你的机器

Tokenhush 自身能发往厂商的流量只有两个可关类别——更新检查与规则同步。关闭开关后,两者都会在发起任何网络请求前短路。

  • 更新检查

    仅在 tokenhush update 时运行。关闭方式:TOKENHUSH_NO_UPDATE_CHECK=1。

  • 规则同步

    仅在 tokenhush rules sync 时运行。关闭方式:TOKENHUSH_NO_RULE_SYNC=1。

开源

启动网关,让工具指向它

以 Apache-2.0 开源、公开构建。装好二进制,运行 tokenhush run,设置一个 base URL——配置指南覆盖全部 14 个工具。

  • Apache-2.0
  • 不装根证书