面向 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_ | 开启 |
| jwt | JSON Web Token | 开启 |
| pem | PEM 私钥头(-----BEGIN … PRIVATE KEY-----) | 开启 |
| luhn | 可通过 Luhn 校验的卡号 | 开启 |
| 域名为已知公共后缀(.com、.co.uk 等)的邮箱地址 | 开启 | |
| entropy | 高熵字符串——默认关闭,因为它在真实 agent 流量上的误报会破坏工具调用 | 关闭(按需开启) |
十四个工具,各一条配置片段
任何支持自定义 base URL 的客户端都能接入。以下 14 个工具自带 tokenhush env 生成的现成片段;Anthropic 风格客户端填裸 origin,OpenAI 兼容客户端填 /v1。
- Claude CodeANTHROPIC_BASE_URL
- Codex CLI~/.codex/config.toml
- AiderOPENAI_API_BASE / ANTHROPIC_API_BASE
- ClineOpenAI Compatible base URL
- Roo CodeOpenAI Compatible base URL
- opencodeopencode.json
- Qwen CodeOPENAI_BASE_URL / ANTHROPIC_BASE_URL
- Charm Crushcrush.json
- Zedsettings.json
- Continue.dev~/.continue/config.yaml
- Open WebUIOPENAI_API_BASE_URL
- GooseOPENAI_HOST + OPENAI_BASE_PATH
- OpenHandsLLM_BASE_URL
- Kilo CodeOpenAI Compatible base URL
用别的客户端?把它的 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 的客户端。 |
仅回环,不装根证书
Tokenhush 绑定 127.0.0.1,主机存在 IPv6 回环时另绑 [::1],并对每个请求校验 Host 白名单。它从不终止 TLS,因此不需要根证书,也不做系统级拦截。
- 没有需要系统级信任的东西没有根证书、不终止 TLS,控制面也只有唯一接口:带每次运行令牌的 GET /status。
- 两种 base URL 形态Anthropic 风格客户端填裸 origin;OpenAI 兼容客户端填 /v1。
# Anthropic 风格客户端
http://127.0.0.1:8787
# OpenAI 兼容客户端
http://127.0.0.1:8787/v1失败时收紧,而不是放开
检测器出错时请求会被拒绝,而不是未经脱敏就转发。编码、体积与时限各自都有明确的拒绝方式,不会静默地发出半成品。
- 没有部分转发超过内存守卫的请求体在任何上游连接之前即被拒绝;超过缓冲上限的响应在提交前返回 502。
- 不猜编码非 identity 的 Content-Encoding 直接以 415 拒绝,而不是解码后再检测。
403 body_too_large
415 unsupported Content-Encoding
502 response over the buffer cap
504 response past the timeout在编译期扩展
内置检测器、签名规则包与你自己的 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。