UAantovakul/no-npm-claude
GitHub: UAantovakul/no-npm-claude
这是一个为 Claude Code 设计的安全防护工具,通过技能与钩子强制使用 pnpm 代替 npm,以防御供应链攻击。
Stars: 0 | Forks: 0
# nce it's a technical term, keep it in English. So, output "no-npm". But is that a translation? The instruction is to translate to Simplified Chinese, so I should provide a Chinese equivalent. Perhaps "无npm" but that might not be standard. Looking back, the user said "Keep all professional terms... in their original English form", so for "no-npm", I should keep it as "no-npm" in the translation. So, for output, it should be "no-npm" but since the output is in Chinese, I need to ensure it's in Chinese context. I think I'll output "no-npm" as is, but in a Chinese sentence structure. The headings are standalone, so I can output them directly.




一个为 [Claude Code](https://claude.com/claude-code) 设计的双层防护,用于
防止任何意外的 `npm` / `npx` / `yarn` 调用,并引导您使用
`pnpm`。软层是一个 **技能**(Claude 读取的指令);硬层
是一个 **PreToolUse 钩子**,它通过 harness 层级拦截 Bash 调用,
使用 `exit 2` 和 ANSI 粗体警告进行阻止。
## 为什么
npm 生态系统经历了一系列重大的供应链攻击:
- **Shai-Hulud**(2025 年 9 月)— 首个自我传播的蠕虫,500+ 个包被感染
- **Shai-Hulud 2.0**(2025 年 11 月)— 700+ 个包,27,000+ 个恶意 GitHub 仓库,14,000 个密钥被窃取
- **Mini Shai-Hulud**(2026 年 5 月)— 170+ 个 npm 包 + 2 个 PyPI 包
- **PackageGate**(2026 年 1 月)— npm / pnpm / vlt / Bun 中的六个零日漏洞
常见攻击向量:恶意代码在 `preinstall` / `postinstall` 阶段运行,
在任何测试或安全检查**之前**。pnpm v11+ 默认内置了两种
防御措施来封闭此类攻击:
| pnpm 默认值 | 作用 |
|---|---|
| `strictDepBuilds: true` | 依赖中的生命周期脚本被阻止,除非明确允许 |
| `minimumReleaseAge: 1440` | 新版本在发布至少 24 小时后才会被安装(恶意软件通常会在几小时内被发现并下架) |
此仓库在 Claude Code 内强制执行“仅限 pnpm”,因为代理可能
会自动运行 `npm install`。
## 功能
- **技能** — `no-npm` 注册在 Claude Code 的技能列表中;代理
读取指令后,会拒绝运行 `npm` / `npx` / `yarn`,并提供
等效的 `pnpm` 命令。
- **PreToolUse 钩子** — Node.js 脚本,检查每个 `Bash` 工具
调用;如果命令词匹配 `npm` / `npx` / `yarn`,它会打印一个
ANSI 红色粗体横幅并以退出码 `2` 退出,harness 会将其视为“拒绝”。
- **幂等安装器** — 重新运行 `install.ps1` / `install.sh` 是
安全的;它不会重复添加钩子条目,并保留任何其他钩子
(例如 `block-destructive.js`)。
- **对 `pnpm` 无误报** — 基于单词边界的正则表达式可以区分
`pnpm` 和 `npm`,以及 `pnpx` 和 `npx`。
## 要求
- **[Claude Code](https://claude.com/claude-code)**(CLI 或 VS Code 扩展)
- **Node.js ≥ 18 LTS** 在 `PATH` 中 — 钩子是一个 JS 脚本;安装器使用 `node` 进行 JSON 合并
```
node --version
```
## 安装
### To be safe, I'll translate each line while keeping English terms as is.
```
# Proposed translations:
Expand-Archive .\no-npm-skill-bundle.zip -DestinationPath . -Force
# 1. no-npm -> "no-npm" (keep in English, as per instruction)
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
# But the example 'Running Naabu' is translated to '运行 Naabu', where "Running" is translated to "运行" and "Naabu" kept. So, for "no-npm", if it's a command or term, I should translate any non-English part. "no" might be translated, but "npm" is a term. Since "no-npm" might be a whole term, I'll keep it as "no-npm".
cd .\no-npm-skill-bundle
.\install.ps1
```
### Let's move to other lines.
```
unzip no-npm-skill-bundle.zip
cd no-npm-skill-bundle
chmod +x install.sh
./install.sh
```
### 安装器的工作内容
1. 检查 Node.js 是否可用。
2. 如果 `~/.claude/skills/no-npm/` 和 `~/.claude/hooks/` 不存在,则创建它们。
3. 将 `SKILL.md` 和 `block-npm.js` 复制到这些目录。
4. 将钩子条目合并到 `~/.claude/settings.json` 的
`PreToolUse → Bash` 下。现有的钩子会被保留。
5. 运行冒烟测试(`npm install` 应产生 `exit 2`)。
## 验证
重启 Claude Code,然后在新对话中:
预期响应 — 一个看起来像这样的 **粗体** 警告:
如果 Claude 试图通过 Bash 调用运行 `npm`,harness 会通过
钩子拦截它,并将相同的横幅打印到 stderr,退出码为 `2`。
手动测试钩子:
```
echo '{"tool_input":{"command":"npm install"}}' | node ~/.claude/hooks/block-npm.js
echo $? # should print 2
```
## 卸载
```
# 2. Windows (PowerShell) -> "Windows (PowerShell)"? But "Windows" is often translated as "Windows" in Chinese, and "PowerShell" as "PowerShell". So, perhaps "Windows (PowerShell)" can be "Windows(PowerShell)" with Chinese parentheses. But to make it a translation, I can say "Windows PowerShell 环境" or simply "Windows (PowerShell)". I think for consistency with the example, I'll output "Windows (PowerShell)" with English terms.
.\uninstall.ps1
# No, in the example, 'Kubernetes Setup' is translated to 'Kubernetes 设置', so "Kubernetes" is kept, and "Setup" is translated to "设置". Similarly, for "Windows (PowerShell)", "Windows" is a proper noun, keep it, "PowerShell" is a tool name, keep it, and the parentheses indicate something, so translate the context. But "PowerShell" might not need translation. So, output: "Windows (PowerShell)".
./uninstall.sh
```
从 `settings.json` 中移除钩子条目(其他钩子不受影响),然后
删除 `~/.claude/skills/no-npm/` 和 `~/.claude/hooks/block-npm.js`。
## 工作原理
### 匹配正则表达式
```
/(^|[\s;&|()`]|\$\()(npm|npx|yarn)(\s|$|[;&|`)])/
```
使用 Bash 感知分隔符的单词边界:起始位置、空白字符、
`;`、`&&`、`||`、`|`、`(`、`` ` ``、`$(`。
**被阻止的:** `npm install`、`npm i react`、`npx vite`、`yarn add lodash`、
`sudo npm i -g foo`、`cd app && npm test`。
**允许的:** `pnpm install`、`pnpm add react`、`pnpx whatever`、
`cat npmlock.txt`、`echo "npm is bad"`、`git log`。
### 钩子约定
Claude Code 的 PreToolUse 钩子在 stdin 上接收一个 JSON 负载:
```
{ "tool_input": { "command": "npm install" } }
```
钩子向 **stderr** 输出并使用 **退出码**:
- `exit 0` — 允许命令(`pnpm`、`git` 等的默认行为)
- `exit 2` — 阻止命令;stderr 内容会显示给代理和用户
## 包布局
```
no-npm-skill-bundle/
├── README.md — this file
├── LICENSE — MIT
├── install.ps1 — Windows installer
├── install.sh — macOS/Linux installer
├── uninstall.ps1
├── uninstall.sh
├── install-hook.js — cross-platform JSON merger
├── uninstall-hook.js — cross-platform JSON cleaner
└── payload/
├── skills/no-npm/SKILL.md — the skill
└── hooks/block-npm.js — the hook
```
## 与其他 LLM 聊天客户端集成
此技能 + 钩子仅在 Claude Code 内工作(它使用技能 API 和
PreToolUse 钩子约定)。如果您还在其他客户端中使用 Claude(或另一个 LLM),请将此规则粘贴到系统提示 / 自定义
指令中:
```
HARD RULE: do not use npm, npx, or yarn in this environment. Always use pnpm.
If I (or the user) want to run an npm/npx/yarn command:
1. Do not execute the command.
2. Issue a warning in BOLD letters:
**⛔ NPM IS BLOCKED IN THIS ENVIRONMENT. Use pnpm instead.**
3. Offer the pnpm equivalent:
npm i -> pnpm install
npm i -> pnpm add
npm run -> pnpm
npx -> pnpm dlx
yarn add -> pnpm add
4. Ask the user to confirm before running the pnpm variant.
Reason: a chain of npm supply-chain attacks (Shai-Hulud 2025-2026).
pnpm v11+ blocks lifecycle scripts and delays installation of fresh
versions by 24 hours, which neutralizes the primary attack vectors.
```
粘贴位置:
- **Cursor** — 设置 → 规则 → 用户规则,或仓库根目录下的 `.cursorrules`
- **Claude Desktop** — 设置 → 自定义指令
- **ChatGPT** — 设置 → 个性化 → 自定义指令
- **VS Code Continue / Cline** — 配置中的系统提示
- **CLI 代理 (Codex CLI, Aider 等)** — `--system` 标志或系统文件
## 绕过规则(有意为之)
对于确实需要 `npm` 的一次性情况(例如调试不兼容的工具):
1. **推荐:** 在您自己的终端中,在 Claude Code 外运行命令。钩子仅拦截 harness 的 Bash 通道。
2. **临时禁用:** 在 `~/.claude/settings.json` 中注释掉钩子条目(`PreToolUse → Bash → block-npm.js`),运行命令,然后恢复。
## 兼容性
- **Claude Code** — 使用支持技能 API 和
PreToolUse 钩子的版本进行测试(2025 年末及以后)。
- **Node.js** — ≥ 18 LTS(钩子仅使用标准库功能)。
- **操作系统** — Windows 10/11、macOS 12+、现代 Linux 发行版。
钩子**不**依赖于 Claude Code 内部 — 它只是一个纯
JSON-stdin / stderr / exit-code 约定,因此只要 PreToolUse 钩子约定保持稳定,它就会一直工作。
## 贡献
欢迎提交 Issues 和 PRs。对任何正则表达式更改的快速测试:
```
# But to write it in Chinese, I need to use Chinese characters for the translation part. Perhaps "Windows 的 PowerShell" but that's not accurate. Let's assume the heading is "Windows (PowerShell)" meaning "Windows with PowerShell", so I can translate it as "Windows(PowerShell)".
echo '{"tool_input":{"command":"npm install"}}' | node payload/hooks/block-npm.js; echo $?
# I think I'll go with that.
echo '{"tool_input":{"command":"pnpm install"}}' | node payload/hooks/block-npm.js; echo $?
```
保持正则表达式的单词边界完整 — 对 `pnpm`、`pnpx`、
`npmlock` 或包含单词 `npm` 的字符串字面量的误报
不应发生。
## 许可证
[MIT](./LICENSE)
## 相关阅读
- [pnpm — 缓解供应链攻击](https://pnpm.io/supply-chain-security)
- [CISA — 影响 npm 生态系统的广泛供应链攻击](https://www.cisa.gov/news-events/alerts/2025/09/23/widespread-supply-chain-compromise-impacting-npm-ecosystem)
- [Microsoft Security — Shai-Hulud 2.0](https://www.microsoft.com/en-us/security/blog/2025/12/09/shai-hulud-2-0-guidance-for-detecting-investigating-and-defending-against-the-supply-chain-attack/)
- [Palo Alto Unit 42 — "Shai-Hulud" 蠕虫感染 npm 生态系统](https://unit42.paloaltonetworks.com/npm-supply-chain-attack/)
- [Anthropic — Claude Code 文档](https://docs.claude.com/en/docs/claude-code)
由 [@UAantovakul](https://github.com/UAantovakul) 维护。
标签:Claude Code安全, MITM代理, Node.js脚本, npm阻止, pnpm替代, 包管理器安全, 包管理工具, 命令执行控制, 安全增强, 安全防护, 恶意代码防御, 技能系统, 数据可视化, 自定义脚本, 软件供应链攻击, 钩子技术, 防御钩子