## 注入（Critical）

### 触发信号

- 字符串拼接构造查询（SQL/NoSQL/LDAP/Shell）
- ORM 查询中使用用户输入拼接字符串（非参数化）
- 模板引擎渲染用户输入（`render`、`template`、`compile`、`Handlebars.compile`）
- 表达式语言求值（`eval`、`Function()`、`Expression Language`）

### 关键 Sink

| 注入类型 | Sink 函数 |
|---------|----------|
| SQL 注入 | `query(string)`、`execute(string)`、`raw()`、`$where`、`sequelize.query(string)` |
| NoSQL 注入 | `Collection.find(object)`（用户输入作为查询条件对象）、`$where`、`$regex` |
| 命令注入 | `exec()`、`system()`、`popen()`、`spawn(shell=True)`、`child_process.exec()` |
| 模板注入 | `render(string)`、`compile(string)`、`Template(user_input).render()` |
| LDAP 注入 | `ldap_search(filter=user_input)` |

### 判定流程

1. **识别 Sink**：`Read` 提取变更代码中的危险函数调用，标记 Sink 点
2. **反向追踪 Source**：`find_references` 从 Sink 参数开始反向追踪数据流（最多 5 层），判断参数是否来自用户输入：
   - 追踪变量赋值链：`param → intermediate → sink`
   - 追踪函数调用链：`handler(req) → service.query(param) → db.raw(param)`
3. **检查防御机制**：在 Source → Sink 路径上，`Read` 检查是否存在：
   - 参数化查询（`?` 占位符、ORM 的 `.where({field: value})`）
   - 输入验证（类型转换、白名单校验）
   - 转义/编码（`escape()`、`sanitize()`、`mysql.escape()`）
4. **验证绕过风险**：如存在防御，`Read` 判断是否可绕过：
   - 黑名单过滤（`replace("drop", "")` 可通过 `drdropop` 绕过）
   - 部分参数化（部分字段拼接、部分参数化 → 整体仍可注入）

### 证据构造

确认缺陷后，输出需包含：
- Source（用户输入的来源，含文件:行号）
- Sink（危险函数调用位置，含文件:行号）
- 传播路径（Source → Propagator → Sink 的完整链路）
- 防御机制分析（无防御 / 可绕过的防御）
- 利用场景（具体的注入 payload 示例）

### 排除

- 已使用参数化查询/预处理语句
- ORM 查询使用安全的参数绑定（`.where({name: req.body.name})`）
- 已使用白名单校验（仅允许字母数字，拒绝特殊字符）
- 模板引擎已开启自动转义（如 Jinja2 autoescape、EJS 默认转义）
