关于 Npmguard
Npmguard 是用于安装前筛查 npm 包的 Rust 命令行工具和 MCP 服务,面向开发者及编码 Agent。它结合包风险评分与 Claude Code 钩子,可在命令执行前实施拦截。
主要功能
- 01安装前评估包风险
- 02检查 OSV 恶意软件和名称仿冒
- 03分析安装脚本
- 04输出文本或 JSON 判定
- 05Claude Code 命令钩子
适用场景
- 01安装前检查 npm 包
- 02拦截 Claude Code 的可疑安装
- 03在 CI 中查看包风险判定
- 04让编码 Agent 请求结构化风险检查
MCP 相关
MCP 服务提供 `install_package` 工具,返回 npm 包的结构化风险判定,并通过 stdio 与 MCP 主机通信。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
npmguard
我开发这个工具,是因为太多氛围编程者直接让 AI 以自动模式运行,任由它安装任何想安装的东西,这实在令人震惊。npmguard 会在任何安装脚本运行之前先进行筛查。
Claude Code、Cursor 和 Codex 会自主运行 npm install。没人会停下来问一句:“等等,supabase-mcp-helper 到底是不是真有这个包?”我开发了 npmguard,将其作为 MCP 服务和 CLI,为每个包打分(参考 OSV 恶意软件数据、检查拼写仿冒/slopsquat,以及分析安装脚本),并在生命周期脚本执行之前给出判定。
它以单个 Rust 二进制文件的形式发布,位于 npm 之外。这很重要:这个防护闸门不会被它要防范的供应链投毒。

npmguard install lodahs 是 lodash 的真实拼写仿冒包,npmguard 会在生命周期脚本运行之前拒绝安装:

也提供 GIF 或 MP4 版本。针对 npm 注册表的实时判定。lodahs 位于 OSV 的恶意软件命名空间中(MAL-2025-25502)。主题:atlas-ragnarok。使用 sh docs/_theme/gen.sh 重新生成(需要 vhs、ffmpeg、webp、pillow、numpy)。
为什么
2025 年至 2026 年间,npm 生态系统接连遭遇蠕虫式供应链攻击:Shai-Hulud(2025 年 9 月)、SHA1-Hulud(2025 年 11 月)、Axios 遭入侵(2026 年 3 月)、Mini Shai-Hulud(2026 年 5 月)。它们全都在有人运行 npm install 时,立即通过 preinstall/install/postinstall 脚本执行。成败在安装完成之前就已决定,而不是之后。
我关注的这个漏洞,目前已有的工具都无法弥补:
npq、safe-npm/socket npm、npm-risk都以 npm 包的形式发布。它们运行在自己本该保护你免受其害的东西之上。如果包装器遭到入侵,情况只会更糟。pnpm v10+、Bun 默认禁用生命周期脚本,但前提是你已经不用npm了。绝大多数 npm 用户仍然暴露在风险之中。npm audit、Snyk、Dependabot、lavamoat/allow-scripts擅长进行 CVE 扫描和管理允许列表。但它们不会充当安装前的启发式防护闸门,也没有任何一个能在 Claude Code、Cursor 或 Codex 代表你运行npm install时拦截这些 AI 编码助手。
最后这一点正是我想解决的问题:在安装前进行风险评分,同时为 AI Agent 设置防护闸门,并以单个位于 npm 之外的二进制文件发布。除所查询的注册表外,零运行时依赖。
安装
macOS(Apple Silicon,aarch64)
curl -L -o npmguard.tar.gz \
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.8-aarch64-apple-darwin.tar.gz
tar -xzf npmguard.tar.gz
# Edit the directory name below if the version has changed.
sudo mv npmguard-v0.1.8-aarch64-apple-darwin/npmguard-cli /usr/local/bin/npmguard
sudo mv npmguard-v0.1.8-aarch64-apple-darwin/npmguard-mcp /usr/local/bin/npmguard-mcp
**隔离属性说明:**如果你通过浏览器而非
curl下载,macOS 可能会将二进制文件标记为不可信(出现"cannot be opened…"或Killed: 9)。解压后清除该属性:xattr -dr com.apple.quarantine /usr/local/bin/npmguard /usr/local/bin/npmguard-mcp上述
curl方式可避免此问题;curl不会设置隔离标记。
macOS(Intel,x86_64)
curl -L -o npmguard.tar.gz \
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.8-x86_64-apple-darwin.tar.gz
tar -xzf npmguard.tar.gz
# Edit the directory name below if the version has changed.
sudo mv npmguard-v0.1.8-x86_64-apple-darwin/npmguard-cli /usr/local/bin/npmguard
sudo mv npmguard-v0.1.8-x86_64-apple-darwin/npmguard-mcp /usr/local/bin/npmguard-mcp
Linux(x86_64)
curl -L -o npmguard.tar.gz \
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.8-x86_64-unknown-linux-gnu.tar.gz
tar -xzf npmguard.tar.gz
# Edit the directory name below if the version has changed.
sudo mv npmguard-v0.1.8-x86_64-unknown-linux-gnu/npmguard-cli /usr/local/bin/npmguard
sudo mv npmguard-v0.1.8-x86_64-unknown-linux-gnu/npmguard-mcp /usr/local/bin/npmguard-mcp
Linux(aarch64)
curl -L -o npmguard.tar.gz \
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.8-aarch64-unknown-linux-gnu.tar.gz
tar -xzf npmguard.tar.gz
# Edit the directory name below if the version has changed.
sudo mv npmguard-v0.1.8-aarch64-unknown-linux-gnu/npmguard-cli /usr/local/bin/npmguard
sudo mv npmguard-v0.1.8-aarch64-unknown-linux-gnu/npmguard-mcp /usr/local/bin/npmguard-mcp
Windows(x86_64)
从此处下载 zip 文件:
https://github.com/AyoubTadlaoui/npmguard/releases/latest/download/npmguard-v0.1.8-x86_64-pc-windows-msvc.zip
解压后,将 npmguard-cli.exe 和 npmguard-mcp.exe 放到 %PATH% 中的某个位置,例如 C:\tools\。
编辑上方 URL 中的版本字符串,即可指定特定版本。
从源代码构建(Rust 用户)
需要 Rust 1.75 或更高版本。
cargo install --git https://github.com/AyoubTadlaoui/npmguard --bin npmguard-cli
cargo install --git https://github.com/AyoubTadlaoui/npmguard --bin npmguard-mcp
安装后,CLI 二进制文件名为 npmguard-cli;如果你更喜欢使用 npmguard,可为它设置别名:
# bash / zsh
echo 'alias npmguard=npmguard-cli' >> ~/.bashrc # or ~/.zshrc
解压前,请使用已发布的校验和验证下载文件:
# Replace the filename to match your platform.
shasum -a 256 -c <(grep npmguard-v0.1.8-aarch64-apple-darwin.tar.gz SHA256SUMS.txt)
所有预构建的二进制文件都列在 Releases 页面上。Homebrew tap、Scoop bucket 和 curl … | sh 安装脚本将随沙箱层一同在 v0.2 发布。
Docker(仅 npmguard-mcp)
docker pull ghcr.io/ayoubtadlaoui/npmguard-mcp:latest
docker run --rm -i ghcr.io/ayoubtadlaoui/npmguard-mcp:latest
Docker 镜像主要用于 MCP 目录和 CI。本地使用时,请安装原生二进制文件。该镜像仅包含 npmguard-mcp(不含 CLI),以非 root 用户身份运行,且不公开任何端口。MCP 主机通过 stdio 通信。
快速入门:CLI
# Evaluate the latest version, no install.
npmguard check axios
# Pinned version, JSON output (machine-readable for CI).
npmguard check --json @ctrl/[email protected]
# Install path: v0.1 prints the verdict and stops; v0.2 will run `npm install`
# inside the sandbox layer if the verdict allows it.
npmguard install [email protected]
# Auto-accept warn-level (still refuses block-level).
npmguard install --yes some-fresh-package
示例输出:针对注册表的实时判定结果:
npmguard [email protected] → score 115 / 200 (block, thresholds warn=30 block=70)
10 pts SoleMaintainer single maintainer: adam_baldwin
25 pts Typosquat name 'lodahs' is 1 edit away from popular package 'lodash'
80 pts KnownCve 1 CONFIRMED MALICIOUS by OSV for this version: MAL-2025-25502
blocked: refusing to install lodahs (score 115 ≥ block threshold 70)
所有标志:
| 标志 | 默认值 | 含义 |
|---|---|---|
--json | false | 以 JSON 而非彩色文本输出判定结果 |
--no-color | false | 禁用 ANSI 颜色转义序列 |
--no-cache | false | 跳过本地 SQLite 判定缓存 |
-v / -vv | warn | 提高日志详细程度 |
--yes(仅安装时) | false | 自动接受警告级判定;阻止级判定仍会拒绝 |
快速入门:MCP
npmguard-mcp 通过 stdio 使用 Model Context Protocol。将二进制文件加入 PATH 后,请按照下方对应工具的说明为你的 Agent 注册它。
Claude Code
使用官方 claude mcp add CLI。无需手动编辑 JSON:
# Adds npmguard to your user-level config (~/.claude.json), available in all projects.
claude mcp add --transport stdio --scope user npmguard -- /usr/local/bin/npmguard-mcp
确认已注册:
claude mcp list
若要将其限定在单个项目中(存储在项目根目录的 .mcp.json 中,可安全提交):
claude mcp add --transport stdio --scope project npmguard -- /usr/local/bin/npmguard-mcp
Cursor
在配置中添加 mcpServers 块。使用全局文件以便在每个工作区启用,或使用项目文件将其限定在一个仓库中。
全局(~/.cursor/mcp.json):
{
"mcpServers": {
"npmguard": {
"command": "/usr/local/bin/npmguard-mcp"
}
}
}
项目范围(仓库根目录下的 .cursor/mcp.json):
{
"mcpServers": {
"npmguard": {
"command": "/usr/local/bin/npmguard-mcp"
}
}
}
如果安装位置不是
/usr/local/bin/,请编辑command路径。
Codex CLI
Codex 通过 ~/.codex/config.toml 支持 stdio MCP 服务。添加一个 [mcp_servers.npmguard] 表:
[mcp_servers.npmguard]
command = "/usr/local/bin/npmguard-mcp"
若要将其限定在单个项目中,请在仓库根目录创建 .codex/config.toml,并添加相同的块(仅适用于 Codex 已标记为受信任的项目)。
如果你安装在其他位置,请编辑
command路径。参考:Codex MCP 文档
MCP 工具返回的内容
npmguard-mcp 暴露了一个工具 install_package(name, version?),返回模型可据此采取行动的结构化判定:
{
"package": "lodahs",
"resolved_version": "0.0.1-security",
"level": "block",
"score": 115,
"signals": [
{ "kind": "SoleMaintainer", "points": 10, "detail": "single maintainer: adam_baldwin" },
{ "kind": "Typosquat", "points": 25, "detail": "name 'lodahs' is 1 edit away from popular package 'lodash'" },
{ "kind": "KnownCve", "points": 80, "detail": "1 CONFIRMED MALICIOUS by OSV for this version: MAL-2025-25502" }
],
"recommendation": "Block: do NOT install this package without explicit user override. Present the signals and ask the user to confirm."
}
模型会在自己的消息中收到建议。因此,即使用户说了 “需要什么就安装什么”,助手也能收到结构化信号并停下来询问。
确定性强制执行(Claude Code hook)
MCP 仅提供建议,hook 则不然。
MCP 集成(npmguard-mcp)允许 Claude Code 在安装软件包前询问 npmguard。它效果很好:模型会看到风险判定,并据此采取行动。但它仍然只是提供建议。模型可以自行决定是否调用工具;注意力不集中的模型或被越狱的模型可能会跳过它。
hook 子命令则不同。Claude Code 的运行机制会在每次 Bash 工具调用时自动运行 PreToolUse hooks,在命令执行前。模型无法干预。它不能跳过、绕过 hook,也不能靠说辞逃过 hook。这正是阻止行为切实有效而非流于形式的原因。
设置(一个命令)
# Installs into ~/.claude/settings.json, active in every Claude Code project.
npmguard hook install
# Or scope it to a single project (writes .claude/settings.json in the cwd).
npmguard hook install --scope project
然后重启 Claude Code(或重新加载窗口)。从那时起,Claude Code 尝试运行的每条 Bash 命令都会先经过 npmguard hook handle。
移除 hook:
npmguard hook uninstall # user-level
npmguard hook uninstall --scope project
hook 的作用
- Claude Code 想要运行一条 Bash 命令,例如
npm install some-package。 - 运行机制通过 stdin(JSON)将命令发送给
npmguard hook handle。 - npmguard 会解析命令,查找安装软件包的调用。非安装命令(
ls、git、npm run build等)会立即放行,不进行网络调用。 - 对每个检测到的软件包,都会运行现有风险引擎(信号和评分方式与
npmguard check相同)。 - npmguard 会将决策 JSON 写入 stdout:
- 阻止判定 →
deny:Claude Code 会拒绝该命令,并告知模型原因。 - 警告判定 →
ask:Claude Code 会显示相关信号并询问用户是否确认。 - 正常判定 →
allow:命令会静默执行。 - 网络错误 →
ask,并附带警告消息。未经验证的软件包绝不会被静默放行;基础设施故障也绝不会导致硬性拒绝。
- 阻止判定 →
如实说明局限性
| 局限性 | 状态 |
|---|---|
| 仅支持 Claude Code。 Cursor 和 Codex 尚未提供类似的工具调用前 hook API。在提供该 API 之前,它们仍然只能依赖 MCP 提供建议。 | v1 |
不拦截裸 npm install(不带软件包参数)。 恢复 lockfile(不带参数运行 npm install)会被视为直接放行。只检查包含显式软件包名称的命令。 | v1 |
可能在解析器层面被规避。 精心构造或经过混淆的命令(eval、shell 变量展开、heredoc 等)可以绕过命令解析器。要实现全面强制执行,需要 v0.2 的 npm-wrapper + sandbox 层;该层会包装 npm 本身,而不是解析 shell 字符串。 | v1 |
仅识别 npm / yarn / pnpm / bun。 安装命令(npm install/i/add、yarn add、pnpm add/install/i、bun add/install/i)和即时运行器(npx、bunx、npm exec/x、pnpm dlx、yarn dlx、bun x)都会受到拦截。不在此范围内的软件包管理器不会受到拦截。 | v1 |
风险信号
| 信号 | 分值 | 触发条件 |
|---|---|---|
LifecycleScripts | 30 | 软件包定义了 preinstall、install 或 postinstall |
PackageAge | 25 / 10 | 版本发布于 < 7 / 30 天前 |
MaintainerChurn | 20 | 版本发布前存在 > 180 天的发布间隔(休眠软件包重新启用) |
SoleMaintainer | 10 | 软件包恰好只有一位维护者 |
RepoHealth | 15 / 10 | 关联的 GitHub 仓库已归档 / 没有星标且 6 个月内没有提交 |
Typosquat | 25 | 名称与热门软件包仅相差一次 Damerau-Levenshtein 编辑操作(可检测像 lodahs↔lodash 这样的字符互换) |
KnownCve | 80 / 50 / 20 / 10 / 5 | 存在 OSV.dev 安全公告。如果是 MAL-*(OSV 用于确认恶意软件包的命名空间),则为 80。否则按 CVSS 严重 / 高 / 中 / 低级别计分(基础分根据安全公告的 CVSS 向量计算)。 |
Deprecated | 10 | npm 注册表将此版本标记为已弃用 |
ReleaseAnomaly | 40 / 30 / 25 / 15 | 此版本与前一个版本相比存在类似劫持的变化:新增安装脚本(40)、安装脚本中包含经过混淆的高熵载荷(30)、新增顶层依赖项(25),或依赖项数量增长 > 50%(15)。 |
综合分为各项分值之和(最高为 200)。默认阈值:warn ≥ 30,block ≥ 70。可通过配置按项目调整(计划在 v0.2 中提供)。
**权重是初始值,并非科学定论。**我们会根据 corpus/ 进行调整,并随每次发布公开。欢迎提交 PR。
版本管理与发布
npmguard 遵循语义化版本。在项目处于 0.x 阶段时:
- 对最终用户而言,CLI 视为稳定版本。没有主版本号升级时,不会更改标志名称和退出代码。
- MCP 工具接口(
install_package输入 / 输出架构)可能会在不同的0.x版本之间进行小幅增补。任何破坏性变更都会在 CHANGELOG.md 中说明。
带标签的版本会通过跨平台 GitHub Actions 矩阵,将预构建二进制文件发布到 Releases 页面(macOS x86_64 + arm64、Linux x86_64 + arm64、Windows x86_64)。
说明
v0.1 是风险检查器 + MCP 判定门。它还不是真正的 npm 封装器、安装程序或沙箱。
npmguard check和npmguard install都会给出判定结果;实际执行npm install子进程和跨平台沙箱将于 v0.2 推出。请参阅下方的路线图。
路线图(完整的理由以及经过考虑但拒绝的范围,请参阅 ROADMAP.md):
| 阶段 | 概述 |
|---|---|
| v0.1(已发布) | 风险引擎 + CLI + MCP 服务 + SQLite 缓存 + GitHub Releases |
| v0.2 | 真正执行 npm install + 按操作系统划分的沙箱 + 发布异常引擎(逐版本对比 package.json)+ Homebrew/Scoop/AUR/install.sh 分发 |
| v0.3 | 来源 / 签名验证 + 扫描器适配器(--with npm-audit、--with osv-lockfile、--with socket)+ SBOM 生成 |
| v0.4 | npmguard.toml 策略文件 + CI 模式 + 豁免项 |
| v0.5 | 组织预设 + MCP 市场上架(Claude Code、Cursor、Smithery) |
| v1.0 | 冻结的 Rust API、冻结的 MCP 工具架构、冻结的 JSON 输出、集成到 AI 助手默认文档中 |
运行时沙箱(npmguard run npm test)明确不在范围内。关于原因,请参阅 ROADMAP.md § Considered and kept out of scope。
范围限制(v0.1 尚未实现的内容)
诚实是我们的承诺。
**npmguard 无法证明软件包是安全的。**它可以拦截已知的恶意软件包(OSV
MAL-*)、标记仿冒软件包、展示生命周期脚本 / 软件包年龄 / 维护者变动信息,并让 AI 编码 Agent 使用同一套判定机制。仅此而已。下方列出的所有功能最终都将在 v1.0 中加入。请参阅 ROADMAP.md。
v0.1 仍缺少的内容:
- 无法捕获通过所有启发式检查的攻击。
ReleaseAnomaly信号现在会将每个版本与其前一个版本进行对比,并标记常见的接管特征:新增安装脚本、新增依赖项,或经过混淆的安装脚本载荷。但如果接管者只是微妙地修改现有安装脚本的内容,没有明显的高熵数据块,或者将恶意代码放在普通导入代码中,仍可能逃过检测。v0.2 剩余的工作是包装真正的npm install,并对实际运行的脚本进行沙箱隔离。 - 尚未验证 npm 来源证明/软件包签名。 历史来源证明突然缺失,是强烈的接管信号。这会在 v0.3 中实现。
- 尚未对生命周期脚本进行沙箱隔离,也未包装真正的
npm install子进程。 v0.1 会显示判定结果并停止;v0.2 将提供沙箱(landlock / sandbox-exec / Job Object)+--ignore-scripts强制执行 + 按脚本设置的允许列表。 - 无法防范在导入时而非安装时运行的恶意代码。 如果某个软件包在安装时是良性的,但在导入时作恶,这个工具就无法介入。这是运行时沙箱的问题,刻意不在范围之内。请参阅 ROADMAP.md。
- 不能取代
npm audit、Snyk、Socket、Dependabot 或代码审查。 它是额外的一层。v0.3 将添加--with npm-audit/--with osv-lockfile/--with socket适配器,让 npmguard 成为它们之上的策略关卡,而不是一个重复的扫描器。 - 不作任何保证。任何声称“安全”的工具都在撒谎。这个工具只说“缩小爆炸半径”,仅此而已。
参与贡献
欢迎提交 PR 和问题。简而言之:
cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
NPMGUARD_CORPUS=1 cargo test --test corpus -- --nocapture # live network test
一切就绪后,提交 PR。
许可证
MIT。请参阅 LICENSE。
关于作者
Ayoub Tadlaoui(Atlas Kaisar)。来自摩洛哥,自 2016 年起从事软件开发。
“高性能从不接受兼职投入。”
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。