Presend 的 typosquat 检测器误报率有多高?我们实测了自己的数据
How many false alarms does a typosquat detector raise? We measured ours
Presend 开发者公开其免费 API 中 typosquat 检测的误报测量结果:在 top 15,000 PyPI 包上误报从 58 个降至 11 个,npm-high-impact 的 17,338 个包上从 65 个降至 1 个,24 个 typosquat 测试样本仍全部检出。
2026年10月1日。披露:本文内容关于 Presend 免费 API 中的域名仿冒检查,由其开发者撰写。
域名仿冒检测器会将包名与热门名称进行比较,并标记出可疑地接近的名称:reqeusts 与 requests 相邻。难点不在于捕获 reqeusts,而在于不标记 ms、qs 或 typing_extensions,因为一个对所有人都使用的包乱报警的检查会被关掉,然后就什么都抓不到了。
于是我们不再只在域名仿冒样本上测试检查,而是开始在人们实际安装的包上衡量它:PyPI 前 15,000 个包和 npm-high-impact 列表中的 17,338 个包。
我们从哪里开始
9 月 25 日,针对 25 个非常流行的 npm 包运行时,我们的检查标记了其中 12 个。ms 和 qs 与 ws 只差一次编辑;在固定的编辑距离阈值下,每个短名称与另一个短名称都只差一次编辑。它此前只在已知的域名仿冒样本上测试过,在那里看起来没问题。
什么降低了噪声
- 取决于长度的阈值。三个字符或更少的名称完全不进行近似比较;4 到 7 个字符允许一次编辑;8 个或更多允许两次。
- 规范化 PyPI 名称。PyPI 将
typing_extensions、Typing.Extensions和typing-extensions视为同一个项目(PEP 503)。比较原始字符串会把一个包与它自己标记为冲突。 - 信任 npm 作用域。
@aws-sdk/client-sso与@aws-sdk/client-s3只差一次编辑,但一个作用域属于一个组织,因此一个包永远不会被标记为与其自身作用域内的目标冲突。 - 一份经过审核的合法邻近名称列表。一些真实包与某个热门名称很接近:
psycopg、niquests、preact。每一个在列入之前都经过人工检查(仓库、年龄、历史):目前 PyPI 上有 51 个,npm 上有 57 个。我们从不为了消除警告而移除目标。
热门包上的结果:PyPI 上从 58 个被标记降至 11 个,npm 上从 65 个降至 1 个。剩余的 12 个经过审核后被有意保留标记。我们域名仿冒测试集中的全部 24 个名称(热门包的相似名称,其中几个来自真实事件,如 crossenv 和 python3-dateutil)仍被检测到。
当噪声回来时就会失败的测试
如果某个热门包在未经审核的情况下被标记,这三个测量脚本就会失败。对目标列表或合法邻近名称的任何更改都必须通过它们,因此针对一个误报的修复不能悄悄制造其他误报。
数字会漂移
10 月 1 日,即上一次运行的五天后,PyPI 前 15,000 列表发生了变化,四个最近进入该列表的包被标记:djongo(与 django 相邻)、tmol(toml)、orgparse(argparse)和 webp(web3)。这四个都是合法的。对于最新的那个 tmol,它于 2026 年 5 月首次发布在 PyPI 上,我们没有依赖其 PyPI 元数据中的链接(这些链接由发布者填写):我们检查了其可追溯到 2018 年的仓库是否声明了该 PyPI 名称。误报率是一个带有日期的测量值,而不是代码的属性,因此我们现在每周重新运行它。
名称相似度无法捕获什么
- 与每个目标都相距甚远的名称。只有接近热门包列表的名称才会被检查。在我们把
electron加入该列表之前,electorn一直未被注意到。 - 幻觉名称。AI 模型凭空编造、与任何真实包都不相似的包名(slopsquatting)并不是任何东西的拼写错误,因此基于距离的检查会漏掉它。检查包是否存在是另一种检查,Presend 的供应链检查现在会做这件事:在 npm 或 PyPI 上不存在的名称会被报告为
package_not_found。有人已经注册的编造名称是存在的,所以这项检查会通过;因此供应链检查还会把首次发布于 30 天以内的包报告为新包(new_package),从而捕获最近注册的名称。更早注册的则不会被捕获,而在 PyPI 上,一个删除了早期版本的项目也会被报告为新包。10 月 8 日,PyPI 排名前 15,000 的包中有 9 个不到 30 天;npm 高影响列表中则一个都没有。 - 意图。距离只能说明两个名称相近,并不能说明其中一个是恶意的。它是分诊信号,不是恶意软件扫描器。
用同样的方法衡量其他工具
同样的方法适用于任何仿冒域名规则。将其应用于 NVIDIA SkillSpector 的 SC6 规则(使用其自身代码)时,在 PyPI 排名前 15,000 的包上发现了 97 个高严重性误报,在高影响 npm 上发现了 26 个,而我们仿冒测试集的 24 个名称中检测出了 10 个。经过原生修复(PR #647,已合并)后,这些数字变为 6、0 和 24/24(测试集于 2026 年 10 月 6 日更正:移除了两个合法包)。
试一试,复现它
curl "https://presend.pages.dev/api/typosquat-check?ecosystem=PyPI&package=reqeusts"想在不安装任何东西的情况下对自己的依赖项进行测试,把package.json或requirements.txt拖到/check上:文件在你的浏览器中读取,只发送包名(最多 100 个依赖项)。
该检查通过API、MCP 服务器以及一个GitHub Action免费提供,后者会在 CI 中对你的package.json或requirements.txt运行该检查(有每分钟速率限制)。在 Claude Code 和 Cursor 中,预安装钩子会在 agent 安装每个包之前运行 Presend 的供应链检查:不存在的名称会被阻止,新的或可疑的名称会被标记。想对自己的依赖项进行测试,把package.json或requirements.txt粘贴到在线检查中;只会发送包名。脚本和测试集在公开的presend-source仓库中,最新数字(含发布者变更检查)在测量页面上。
我们也在测试团队是否希望在每个拉取请求以及为其 AI 编码 agent 上运行这些检查,作为付费服务。目前尚未开售;如果这对你的团队有帮助,等候名单在这里。
来源:Hacker News · presend.pages.dev