mcpField
P
pkgtruth

pkgtruth

本地服务
github.com/hxckya安全43 天前更新

关于 pkgtruth

pkgtruth 可在安装前检查 npm 和 PyPI 依赖,适用于编码 Agent、CI 和开发者。它结合注册表信息,通过 MCP 工具、命令行工具、Claude Code 钩子和 GitHub Action 标记虚构或有风险的包名。

主要功能

  1. 01检查 npm 和 PyPI 包名
  2. 02检查清单文件和安装命令
  3. 03识别仿冒包及风险信号
  4. 04为每个判定提供依据
  5. 05支持 MCP 服务、命令行、钩子和 Action

适用场景

  1. 01安装前核验 Agent 提议的依赖
  2. 02在 CI 中扫描项目清单
  3. 03在 Claude Code 中拦截可疑安装

MCP 相关

作为 MCP 服务,pkgtruth 提供检查单个包、依赖列表或完整安装命令的工具。编码 Agent 可在添加或安装依赖前读取检查结果及依据。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"hxckya-pkgtruth": {
"command": "npx",
"args": [
"-y",
"pkgtruth"
],
"env": {
"PKGTRUTH_REGISTRY": "<PKGTRUTH_REGISTRY>",
"PKGTRUTH_DOWNLOADS_API": "<PKGTRUTH_DOWNLOADS_API>",
"PKGTRUTH_CACHE_DIR": "<PKGTRUTH_CACHE_DIR>",
"PKGTRUTH_TIMEOUT_MS": "<PKGTRUTH_TIMEOUT_MS>"
}
}
}
}
启动命令npx -y pkgtruth
需要配置的环境变量
PKGTRUTH_REGISTRYAlternate npm registry to verify against. Defaults to https://registry.npmjs.org.
PKGTRUTH_DOWNLOADS_APIAlternate downloads API used for adoption figures. Defaults to https://api.npmjs.org.
PKGTRUTH_CACHE_DIRWhere adoption figures are cached between runs. Defaults to ~/.cache/pkgtruth.
PKGTRUTH_TIMEOUT_MSPer-request timeout in milliseconds. Defaults to 8000.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmpkgtruth0.2.2

工具

3

收录的工具列表 · 更新于 2 周前

参数类型必填说明
namestring是要验证的确切包名,即安装时使用的名称,例如 "express"、"@scope/pkg",或 PyPI 包的 "requests"。不带版本后缀。
ecosystemenum否要查询的注册表。默认为 npm。npm | pypi

详细介绍

pkgtruth

npm CI node license

为 AI 编码 Agent 和 CI 提供关于 npm 和 PyPI 软件包的真实信息。

pkgtruth catches a hallucinated package and a slopsquat

你的 Agent 刚刚写下了 npm install unused-imports。这个软件包并不是它想要的那个代码检查插件。它是攻击者注册的名称,因为模型一直在凭空编造这个名称——此后 npm 已用安全占位包取代了它。

pkgtruth 会在它进入锁文件之前将其拦截——它可以作为 MCP 服务供 Agent 查询,也可以作为用于 CI 的命令行工具、拉取请求中的 GitHub Action,或拒绝安装命令本身的 Claude Code hook。

为什么要做这个项目

大模型会编造软件包名称。对多个模型的测量结果显示,生成的软件包名称中有 19.7% 是幻觉;研究人员重新运行提示词时,其中 43% 的名称每次都会再次出现。

这种可复现性正是整个攻击的关键。攻击者无需入侵维护者、污染构建服务器,也不必寻找漏洞。他们只需观察模型编造了什么,注册该名称,然后等待。这种技术称为垃圾包抢注(slopsquatting),现实中已经发生。

通常的安全建议是,具备软件包管理能力的 Agent 不应在没有审核关卡的情况下安装任何内容。pkgtruth 就是这样的关卡,而且 Agent 可以自行调用。

现实中发现的案例

以下两个名称都是模型可能生成的,而且如今都在 npm 上:

名称实际情况每周安装量正确的软件包
types-node0.0.1-security——npm 清除恶意软件后留下的占位包10@types/node(429M)
socket-io自 2022 年起已弃用,“请改用 socket.io 软件包”1,486socket.io(18M)

模型丢掉 @types/node 的作用域后,就会得到 types-node。npm 于 2024 年 12 月因恶意代码将其移除,但它每周仍有十次安装。

socket-io 并无恶意——它是一个名称容易混淆、已被弃用的软件包。即便如此,它每周仍有 1,486 次安装,这正说明了问题:一个点号和一个连字符就足以造成混淆。

PyPI 上也有同样的情况,只是没有占位包:

名称实际情况每周安装量正确的软件包
sklearn已弃用的兼容包——它自己的声明写着“请改用 scikit-learn”321,887scikit-learn(42.6M)
pytorch一个诱饵包,唯一内容是“以 PyTorch 命名的软件包是 torch”41,026torch(14.4M)

这两个名称的拼写都与其所冒充的软件包相去甚远,所以 pkgtruth 也会读取弃用声明写了什么:如果声明提到一个更受欢迎的软件包,那么这个名称就是证据。

npx pkgtruth check types-node socket-io
npx pkgtruth check -e pypi sklearn pytorch

这两个案例来自对 20 个名称的人工检查。系统化版本覆盖 242 个知名软件包,枚举每个软件包的所有可能拼错形式,并在每周一重新生成,详见 SLOPSQUATS.md。其中 A 节仅列出 npm 的安全占位包:这些名称曾因恶意软件被 npm 清除,但本周仍有人安装。新增或移除名称的每周变动会作为发布版本公布,因此可以通过发布动态源关注实时列表,无需持续查看代码仓库。

安装

作为 MCP 服务(供编码 Agent 使用)
{
  "mcpServers": {
    "pkgtruth": {
      "command": "npx",
      "args": ["-y", "pkgtruth"]
    }
  }
}

现在可使用三个工具:

工具使用时机
check_package准备添加、导入或推荐一个依赖项时(ecosystem: "npm" | "pypi",默认为 npm)
check_dependencies准备编写 package.json / requirements.txt 时
check_install_command准备运行 npm install …、npx …、pip install … 时——将完整命令传给它
作为 Claude Code 钩子(安装命令本身会被拦截)

MCP 工具只有在 Agent 记得调用时才有用。PreToolUse 钩子会改为检查每条 shell 命令,并在包名是虚构的或有危险时,拒绝执行 npm install、npx、 pnpm add、yarn add、bun add、pip install、uv add、poetry add 等命令。将以下内容添加到 ~/.claude/settings.json(适用于每个项目)或 .claude/settings.json (适用于单个仓库,可提交到仓库):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "npx -y pkgtruth hook" }]
      }
    ]
  }
}

不指定包名、不安装任何内容的命令——例如单独的 npm install、git、测试,以及对 node_modules 中已有工具运行的 npx <bin>——都会直接通过,不会发起网络请求。被拦截的命令会连同证据一起作为拒绝结果返回给 Agent, 这样它就可以改用真实的包:

pkgtruth blocked this command: 1 of 2 package(s) must not be installed as-is.
  ✖ crossenv DANGER — npm replaced this package with a security placeholder (0.0.2-security).
    The name was used to publish malicious code. Package is 1 edit(s) from "cross-env",
    which has 22,155,059 weekly downloads (15,418x this one). Confirm you meant this
    package and not that one.

添加 --fail-on caution,也会拦截无法验证的包。使用 "command": "pkgtruth hook" 执行 npm install -g pkgtruth,可在每次调用时跳过 npx 解析(实测:通过 npx 每条命令约需 0.2 秒,直接执行约需 0.03 秒)。钩子会从 Claude Code 的 JSON 中读取 tool_input.command,或从任何其他通过管道传入命令的 Agent 读取普通命令字符串;拦截命令时会以状态码 2 退出,并返回 permissionDecision: "deny"——没有可关闭此功能的环境变量,因为 Agent 可以控制其运行命令的环境。

作为 Claude Code 插件(一次安装,同时提供服务和钩子)
/plugin marketplace add hxckya/pkgtruth
/plugin install pkgtruth@pkgtruth

该插件(plugin/)会一并注册 MCP 服务和上述钩子,并固定使用随插件发布的 npm 版本。

作为 CLI(供个人和 CI 使用)
npx pkgtruth check express unused-imports          # npm (default)
npx pkgtruth check -e pypi requests sklearn        # PyPI
npx pkgtruth scan .                                 # every manifest in the directory

scan 会读取 package.json、requirements*.txt 和 pyproject.toml (PEP 621 和 Poetry),对照各自的注册表逐项检查;如果有任何阻止项,就会以非零状态码退出,因此可直接用于 CI。

作为拉取请求检查门禁(GitHub Action)

hxckya/pkgtruth-action(位于 GitHub Marketplace)会在每个拉取请求上运行扫描,发布一条置顶评论并附上证据;当检查结果为 HALLUCINATED 或 DANGER 时,检查会失败:

on:
  pull_request:
    paths: ['package.json', '**/package.json']
permissions:
  contents: read
  pull-requests: write
jobs:
  pkgtruth:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: hxckya/pkgtruth-action@v1

本仓库也使用它作为门禁——参见 .github/workflows/gate.yml。该工作流还会通过对一个故意配置错误的测试样例运行门禁,证明门禁确实可以失败。

检查内容

信号含义
未在注册表中包名是虚构的,没有可安装的内容。
npm 安全占位符npm 已移除以此名称发布的恶意代码。
冒充热门包名称几乎相同,但采用率低得多;或者弃用通知中点名了你实际想要的包(sklearn → scikit-learn、pytorch → torch)。
已撤回(PyPI)最新版本的所有文件均已被其维护者撤回。
安装时脚本preinstall/install/postinstall 会在 npm install 时运行代码。
已弃用上游已建议停止使用。
非常新 / 几乎无人采用发布仅数天,安装量只有个位数。
没有仓库没有可供审查的源代码。
无人维护多年来没有发布过新版本。

判定结果为 SAFE、CAUTION、DANGER、HALLUCINATED 或 UNKNOWN。每个结果都会附上相应证据——Agent 不应盲目信任 DANGER,你也一样。

设计说明

网络故障绝不会放行。 如果无法访问注册表,判定结果将是 UNKNOWN,绝不会是 SAFE。网络降级不能悄无声息地让安全检查变成空操作。

热门包不会被标记——这是经过测量的结果,而非断言。误报审计 使用检测器检查了 240 个知名包的直接依赖闭包:经过内置的第二轮检查后,1,523 个真实包中,阻止级判定为 0,UNKNOWN 为 0,CAUTION 为 40(已弃用或无人维护——这些判断属实,默认不会阻止)。乱报警的门禁会被关闭;这个门禁有数据支撑。

无需构建步骤。 只有两个直接依赖——MCP SDK 和 zod,且仅服务端需要。运行 npx pkgtruth 即可立即启动。

限制

请在信任它之前阅读以下内容:

  • 仅支持 npm 和 PyPI。 暂不支持 crates.io、Go modules 和 RubyGems。
  • PyPI 没有清除标记。 npm 会在移除恶意软件后留下 -security 占位符;PyPI 则会删除项目,因此已清除的 PyPI 名称只会被判定为 HALLUCINATED。PyPI 也没有搜索 API——系统会根据每日更新的下载量最高的 15,000 个项目快照查找近似名称,因此不会发现冒充冷门包的项目。
  • 仅检查注册表元数据。 它不会分析包的源代码,因此带有恶意载荷、但看起来合法的包仍可能通过检查。
  • 不能替代 npm audit 或 Snyk。 它们会查找你已信任的代码中的已知 CVE。pkgtruth 关注的是更早一步的问题:这个包到底该不该出现在这里?
  • 新发布的合法包会被标记为 CAUTION。 这是有意为之。新近发布本身确实是一个风险信号;请使用 --fail-on danger,这样就不会因此阻止安装。

选项

--json              Machine-readable output
--fail-on <level>   danger (default) | caution

--fail-on caution 也会阻止无法验证的包,因为“我们无法检查”不等于通过检查。

退出代码:0 表示无问题,1 表示发现阻止级包,2 表示用法或运行时错误。

配置

变量默认值用途
PKGTRUTH_TIMEOUT_MS8000每个请求的超时时间
PKGTRUTH_RETRIES3对 429/5xx/网络错误进行重试
PKGTRUTH_MAX_CONCURRENCYper-host覆盖请求节流设置
PKGTRUTH_REGISTRYnpm替代注册表
PKGTRUTH_DOWNLOADS_APInpm替代下载量 API
PKGTRUTH_PYPI / PKGTRUTH_PYPISTATSpypi.org / pypistats.org替代 PyPI 端点
PKGTRUTH_PYPI_TOPhugovk top-pypi-packagesPyPI 相似包检查所用的替代热门度快照
PKGTRUTH_CACHE_DIR~/.cache/pkgtruth缓存采用数据的位置
PKGTRUTH_DISK_TTL_MS6 hours缓存数据的有效时长
PKGTRUTH_NO_DISK_CACHEunset设为 1 可禁用缓存
关于速度和速率限制

采用数据来自 npm 的下载量 API,该 API 会限制突发请求,且无法批量查询带作用域的名称——如果项目依赖了多个 @scope/pkg,每次扫描都会耗尽全部请求额度。

以下三种措施可控制这一问题:批量端点可通过一次请求解析所有不带作用域的名称;对该主机的请求会串行节流;数据会在磁盘上缓存六小时。每周下载量变化缓慢,因此六小时前的数据同样可靠。

热缓存扫描约 18 个依赖项需要约 1.4 秒。大型扫描如果从下载量 API 收到 429 响应,部分包会在第一轮检查中被标记为 UNKNOWN;随后,每个入口点都会在短暂等待后,仅串行复查这些名称。在对 1,523 个包进行的审计中,第二轮检查将它们全部确认。被限流的查询绝不会变成 SAFE。

缓存数据会按来源 API 区分,因此将 PKGTRUTH_DOWNLOADS_API 指向私有注册表时,不会复用 npm 的数据。

贡献

欢迎在 github.com/hxckya/pkgtruth 提交问题和拉取请求。

有两类报告尤其有用:被误报的合法软件包,以及漏网的恶意软件包。两者都值得编写回归测试。

npm test                 # offline
npm run test:online      # includes live registry checks

许可证

MIT © hxckya

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。