一款开发者优先的代码库漏洞扫描器,结合静态 AST 分析与 Docker 动态攻击验证,在代码发布前自动检测 SQL 注入、XSS、硬编码密钥和脆弱依赖项,提供低误报的可操作安全发现。
# 🛡️ Codebase 漏洞扫描器
**一款在代码发布前捕捉真实漏洞的预检安全扫描器。**
[](https://nodejs.org)
[](https://www.typescriptlang.org)
[](https://python.org)
[](./LICENSE)
[](https://code.visualstudio.com)
*静态分析 · 动态验证 · 密钥检测 · 依赖审计 —— 集于一身。*
## 这是什么?
**Codebase Vulnerability Scanner (CVS)** 是一款开发者优先的安全工具,介于代码编辑器和 CI 流水线之间。它将四个独立的扫描引擎整合为一次统一的扫描——为您提供经过确认且具有可操作性的结果,而不是一大堆嘈杂的误报。
它有两种工作模式:
- **VS Code 扩展** —— 只需一条命令即可扫描您打开的项目,并在功能丰富的侧边栏面板中内联查看结果
- **CLI** —— 通过 `node packages/cli/dist/index.js scan ./your-project` 集成到任何构建流水线中
与仅进行静态分析的传统 SAST 工具不同,此扫描器通过以下方式**证明**漏洞是真实的:
1. 通过 AST 遍历检测可疑代码模式(静态)
2. 在 Docker 中启动您的应用
3. 向运行中的应用发送真实的攻击 payload
4. 只有在应用实际响应出被利用的证据时,才将结果标记为 `confirmed`
## 目录
- [它能检测什么](#-what-it-catches)
- [支持的语言与框架](#-supported-languages-and-frameworks)
- [工作原理 —— 详解](#-how-it-works--in-detail)
- [第 1 阶段:插件检测](#stage-1-plugin-detection)
- [第 2 阶段:静态分析 —— AST 污染追踪](#stage-2-static-analysis--ast-taint-tracking)
- [第 3 阶段:密钥扫描器](#stage-3-secrets-scanner)
- [第 4 阶段:依赖审计器](#stage-4-dependency-auditor)
- [第 5 阶段:Docker 编排](#stage-5-docker-orchestration)
- [第 6 阶段:动态攻击引擎](#stage-6-dynamic-attack-engine)
- [第 7 阶段:结果存储与差异比对](#stage-7-findings-store-and-diffing)
- [IPC 层](#ipc-layer-extension-communication)
- [架构](#-architecture)
- [安装说明](#-installation)
- [用法](#-usage)
- [VS Code 扩展](#vs-code-extension)
- [CLI](#cli)
- [配置参考](#configuration-reference)
- [解读您的结果](#-understanding-your-results)
- [常见问题](#-faq)
- [许可证](#-license)
- [联系方式](#-contact)
## 它能检测什么
| 漏洞 | 检测方法 | 严重程度 |
|---|---|---|
| **SQL 注入**(基于错误、布尔盲注、基于时间) | AST 污染追踪 → 动态攻击 | Critical |
| **跨站脚本攻击 (XSS)** | AST 污染追踪 → 动态验证 | High |
| **不安全的直接对象引用 (IDOR)** | 路由模式分析 → 动态探测 | High |
| **硬编码的密钥和 API 密钥** | 正则表达式规则 + Shannon 熵分析 | Critical / High |
| **存在漏洞的依赖项** | 查询 OSV.dev 数据库 | Critical → Low |
| **安全配置错误** | 实时 HTTP 标头和路径探测 | Medium / Info |
## 支持的语言与框架
扫描器采用**插件架构** —— 每种语言/框架都有各自的插件来实现标准接口。核心引擎是与框架无关的。
| 插件 | 框架 | 检测信号 | AST 引擎 |
|---|---|---|---|
| `plugin-express` | Node.js + Express.js | 包含 `express` 依赖的 `package.json` | `@babel/parser` + `@babel/traverse` |
| `plugin-python` | Python + Flask | `requirements.txt`, `app.py`, `pyproject.toml` | Python `ast` 模块(通过 `parser.py`) |
**计划支持:** Django, FastAPI, Spring Boot, Laravel
如果没有插件与您的项目匹配,扫描器仍会运行**密钥检测**和**依赖审计** —— 依赖插件的阶段将被跳过并发出警告。
## 工作原理 —— 详解
每次扫描都会运行由 `packages/cli/src/scanner.ts` 管理的确定性 7 阶段流水线。
### 第 1 阶段:插件检测
```
detectPlugin(config.projectPath) → LanguagePlugin | null
```
**插件注册中心**(`packages/cli/src/plugin-registry.ts`)会遍历所有已注册的插件,并调用每个插件的 `.detect(projectPath)` 方法。第一个识别出项目的插件将被选中。检测基于文件系统 —— 无网络调用,无猜测。
- **Express 插件**通过检查 `package.json` 依赖项中是否包含 `express` 键来进行检测
- **Python/Flask 插件**通过检查是否存在 `requirements.txt`, `app.py`, `wsgi.py`, `pyproject.toml` 或 `Pipfile` 来进行检测
### 第 2 阶段:静态分析 —— AST 污染追踪
#### Express / Node.js
Express 插件(`packages/plugin-express/src/`)分两步工作:
**步骤 A —— 路由解析器**(`route-parser.ts`)
使用 `@babel/parser` 将每个 `.js` / `.ts` 源文件解析为完整的抽象语法树 (AST)。然后遍历 AST 查找 Express 路由注册:
```
app.get('/users/:id', (req, res) => { ... })
app.post('/login', handler)
router.put('/profile', ...)
```
每个发现的路由都会记录其 HTTP 方法、路径模式、源文件和行号。
**步骤 B —— 污染追踪器**(`taint-walker.ts`)
对于每个路由处理器,污染追踪器会重新遍历 AST,寻找**污染流** —— 即用户控制的输入(`req.query.*`, `req.body.*`, `req.params.*`, `req.headers.*`)未经清理直接流入敏感接收器的路径。
追踪的接收器:
- **SQLi 接收器:** 数据库对象(`db`, `pool`, `connection`, `client`, `knex`, `sequelize`)上的 `.query()`, `.raw()`, `.execute()`, `.exec()`, `.prepare()`
- **XSS 接收器:** 参数中包含用户输入且未使用已知清理器(`sanitize`, `escape`, `DOMPurify`, `sanitizeHtml` 等)的 `res.send()`, `res.write()`, `res.end()`, `res.render()`
当发现污染流时,追踪器会生成一个**候选项** —— 一条轻量级记录,包含漏洞类型、文件、行号、路由、HTTP 方法、参数名称和参数位置(query/body/params/header)。候选项尚不是最终的发现结果;它们会被传递给攻击引擎进行验证。
#### Python / Flask
Python 插件(`packages/plugin-python/src/`)将 AST 分析委托给原生的 Python 子进程(`parser.py`)以实现准确的 Python 解析。该脚本使用 Python 内置的 `ast` 模块来:
1. 遍历项目目录中的所有 `.py` 文件
2. 识别 Flask 路由装饰器(`@app.route`, `@blueprint.route`)
3. 追踪从 `request.args`, `request.form`, `request.json`, `request.get_json()` 到 SQL 执行调用(`cursor.execute`, `db.execute`)以及响应构建的数据流
4. 生成与 Express 插件产生的相同的 `routes` + `candidates` JSON 结构
这意味着动态攻击引擎对 Flask 和 Express 的处理方式是完全相同的。
### 第 3 阶段:密钥扫描器
```
scanFileForSecrets(filePath, projectPath, config, scanId) → Finding[]
```
对插件发现的每个源文件运行。它执行**两个独立的步骤**:
**步骤 1 —— 基于规则的模式匹配**
从 `packages/cli/src/static/gitleaks-rules.json` 加载规则 —— 这是一组精选的正则表达式,涵盖:
- AWS Access Keys 和 Secret Keys
- GitHub Personal Access Tokens
- Stripe API keys(正式和测试环境)
- Slack Webhook URLs
- 通用的 `password =` / `secret =` / `api_key =` 赋值模式
- JWT tokens
- RSA 私钥标头
- Google API keys
- Twilio account SIDs
每个模式都会针对文件中的每一行进行测试。在标记匹配项之前,扫描器会将其通过**误报过滤器**进行筛选,拒绝匹配常见占位符模式的值(如 `example`, `sample`, `placeholder`, `test-`, `changeme`, UUID 格式, `xxxxxxxx` 等)。
**步骤 2 —— Shannon 熵分析**
对于长度超过 20 个字符且在步骤 1 中*未*被标记的每个字符串字面量,扫描器会计算其 [Shannon 熵](https://en.wikipedia.org/wiki/Entropy_(information_theory))。熵值大于 4.5 比特/字符的字符串在统计学上不太可能是人类可读的文本,无论是否匹配已知模式,都会被标记为可能的密钥。
这可以捕获不符合任何已知模式的 API 密钥、token 和加密材料。
您可以通过 `vuln-scanner.config.json` 扩展或限制这些规则:
```
{
"secrets": {
"additionalPatterns": [
{ "name": "Internal Token", "regex": "MYAPP_TOKEN=[A-Za-z0-9]{32}", "severity": "high" }
],
"excludePatterns": ["generic-api-key"]
}
}
```
### 第 4 阶段:依赖审计器
```
auditDependencies(projectPath, config, scanId) → { findings, warning }
```
读取 `package.json`(对于 Node.js 项目)或 `requirements.txt` / `Pipfile`(对于 Python 项目),提取所有声明的依赖项及其安装版本,并分批查询 **[OSV.dev](https://osv.dev) API**。
OSV(Open Source Vulnerabilities)是一个由 Google 维护的免费、聚合的漏洞数据库,它整合了来自 NVD、GitHub Advisory、npm advisories、PyPI advisories 等的数据。
每个易受攻击的包都会产生一个 `dependency` 类型的发现结果,其中包含:
- 已安装版本与第一个修复版本
- CVE 标识符(如果有)
- 指向 OSV 安全通告的直接链接
- 生态系统(`npm`, `PyPI`)
如果缺少 `package.json` 或无法访问 OSV API,将发出 `DEP_AUDIT_SKIP` 警告,扫描将继续进行。
### 第 5 阶段:Docker 编排
```
bootStack(config) → { success, baseUrl, warning }
```
Docker 编排器(`packages/cli/src/docker/orchestrator.ts`)会在隔离的容器中启动您的应用程序,以便攻击引擎可以向其发送真实的 HTTP 请求:
1. **运行 `docker compose up -d`**,使用配置中的 `composeFile` 路径(默认:`docker-compose.yml`)
2. **等待健康检查** —— 轮询 `http://localhost:{port}{healthCheckPath}`,采用指数退避策略,直到应用响应 200 或达到 60 秒超时
3. **返回基础 URL**(例如 `http://localhost:3000`)供攻击引擎使用
攻击引擎完成后,`teardownStack()` 会运行 `docker compose down` 进行清理,无论成功或失败。
如果 Docker 不可用或缺少 compose 文件,编排器会发出警告,所有污染候选项将成为 `static-only`(未确认)的发现结果 —— 扫描仍将成功完成。
### 第 6 阶段:动态攻击引擎
```
runAttackEngine(baseUrl, candidates, config, scanId) → Finding[]
```
这是静态候选项变为已确认(或被拒绝)的发现结果的地方。引擎(`packages/cli/src/attack/engine.ts`)将每个候选项分派到相应的攻击模块。
#### SQL 注入模块(`attack/sqli.ts`)
对于每个 SQLi 候选项,运行**三层攻击序列**:
| 层级 | 技术 | Payload 示例 |
|---|---|---|
| 1 | **基于错误** | `'`, `''`, `1' OR '1'='1`, `1'; SELECT SLEEP(0)--` |
| 2 | **布尔盲注** | `1 AND 1=1` 对比 `1 AND 1=2` —— 检查响应正文长度是否出现差异 |
| 3 | **基于时间的盲注** | `1'; SELECT SLEEP(3)--`, `1' AND SLEEP(3)--`, `1; pg_sleep(3)--` |
只有当某一层产生确凿证据(响应正文中包含 SQL 错误关键字、可证明的布尔差异,或在 500ms 以下的基准下测量到大于 2.5 秒的时间延迟)时,才会输出发现结果。每一层都会首先建立**基准线**,以排除偶然的差异。
#### XSS 模块(`attack/xss.ts`)
对于每个 XSS 候选项,注入一组针对上下文感知的 payload,以突破常见的 HTML 上下文:
```
">

'>