fimskiy/Evil-merge-detector
GitHub: fimskiy/Evil-merge-detector
检测 Git 仓库中绕过代码审查的邪恶合并提交,帮助发现供应链攻击中通过合并夹带的隐蔽代码改动。
Stars: 5 | Forks: 0
# Evil Merge Detector
[](https://github.com/fimskiy/Evil-merge-detector/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/fimskiy/evil-merge-detector)
[](LICENSE)
[](https://www.buymeacoffee.com/fimskiy)
检测 Git 仓库中的 **evil merge** —— 即# Evil Merge Detector
[](https://github.com/fimskiy/Evil-merge-detector/actions/workflows/ci.yml)
[](https://goreportcard.com/report/github.com/fimskiy/evil-merge-detector)
[](LICENSE)
[](https://www.buymeacoffee.com/fimskiy)
检测 Git 仓库中的**邪恶合并** —— 即包含超出冲突解决方案之更改的合并提交,这些更改对代码审查是不可见的。
## 什么是邪恶合并?
邪恶合并是指引入了在任一父分支中均不存在的更改的合并提交。这些更改:
- **绕过代码审查** —— 审查者看到的是分支差异,而不是合并提交本身
- **难以追踪** —— `git blame` 会指向该合并,而不是某个有意义的提交
- **可能隐藏恶意代码** —— 一种常见的供应链攻击途径
```
feature ──●──────────────────────●── main
\ /
●── evil change ───● ← merge commit contains extra code
/
main ─────●
```
## 安装
**Homebrew:**
```
brew install fimskiy/tap/evilmerge
```
**Go:**
```
go install github.com/fimskiy/evil-merge-detector/cmd/evilmerge@latest
```
**二进制文件:** 从 [Releases](https://github.com/fimskiy/Evil-merge-detector/releases) 下载
## 使用方法
```
# 扫描当前 repository
evilmerge scan
# 扫描特定路径
evilmerge scan /path/to/repo
# 扫描特定 branch(自指定日期起)
evilmerge scan --branch=main --since=2024-01-01
# 仅显示关键 findings
evilmerge scan --severity=critical
# 用于脚本编程的 JSON 输出
evilmerge scan --format=json
# 如果发现任何 warnings 则以代码 1 退出(用于 CI)
evilmerge scan --fail-on=warning
# 详细检查特定 merge commit(含 line diffs)
evilmerge scan --commit=a1b2c3d
# 将扫描限制为 60 秒(适用于非常大的 repository)
evilmerge scan --timeout=60s
```
**示例输出:**
```
Evil Merge Detector v0.1.9
Scanning repository: /path/to/repo (branch: main)
Analyzed 142 merge commits, found 2 evil merges (in 340ms)
SEVERITY COMMIT AUTHOR FILES
----------------------------------------------------------------------------------------------------------
CRITICAL a1b2c3d Merge branch 'feature/auth' dev@company.com config.py
WARNING d4e5f6a Merge branch 'hotfix/payment' dev@company.com utils.js
Re-run with --format=json for full details on each merge.
```
## 严重级别
| 严重性 | 含义 |
|----------|---------|
| **CRITICAL** | 文件在两个分支中均未更改,但在合并中被修改;在合并中添加了新文件;敏感文件(`.env`、`auth`、`crypto` 等)发生更改 |
| **WARNING** | 文件在一个分支中发生了更改,但合并结果与两个父分支均不同 |
| **INFO** | 文件在两个分支中均发生了更改(冲突区域) —— 可能是合法的冲突解决,值得审查 |
## GitHub App
最简单的入门方式 —— 安装一次,组织中的每个 Pull Request 都会被自动扫描。无需更改工作流。
**[从 GitHub Marketplace 安装 →](https://github.com/marketplace/evil-merge-detector)**
- 通过 GitHub Checks 在每个 PR 上自动扫描
- 结果直接显示在 Pull Request 中
- 首次安装时进行完整历史扫描 —— 可捕获过去的事件
- 可在 [evilmerge.dev/dashboard](https://evilmerge.dev/dashboard) 查看扫描历史
- 发现邪恶合并时提供 Slack / webhook 通知
**计划:** 免费(公共仓库,每月 50 次扫描) · 专业版 $7/月(私有仓库,无限扫描,仪表板)
**状态徽章** —— 添加到您的 README 中:
```

```
根据最新扫描结果显示 `passing`(绿色)或 `N found`(红色)。
## GitHub Action
添加到您的工作流以自动检查 PR 是否存在邪恶合并:
```
name: Evil Merge Check
on:
pull_request:
types: [opened, synchronize]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: fimskiy/Evil-merge-detector@v1
with:
fail-on: warning
```
### Action 输入
| 输入 | 描述 | 默认值 |
|-------|-------------|---------|
| `fail-on` | 导致检查失败的最低严重级别(`info`/`warning`/`critical`) | `warning` |
| `severity` | 报告的最低严重级别 | `info` |
| `branch` | 要扫描的分支(默认从 PR 自动检测) | — |
| `since` | 仅扫描此日期之后的合并 (YYYY-MM-DD) | — |
| `version` | 要使用的 evilmerge 版本 | `latest` |
| `upload-sarif` | 将 SARIF 结果上传到代码扫描 | `false` |
### Action 输出
| 输出 | 描述 |
|--------|-------------|
| `evil-merges-found` | 如果发现邪恶合并则为 `true` |
| `evil-merge-count` | 发现的邪恶合并提交数量 |
### 结合 SARIF 上传
```
- uses: fimskiy/Evil-merge-detector@v1
with:
fail-on: warning
upload-sarif: true
```
扫描结果将显示在 **Security → Code scanning alerts** 中,包含严重级别、受影响文件和提交指纹。
## 其他 CI 集成
开箱即用的模板位于 [`examples/`](examples/):
| 平台 | 文件 |
|----------|------|
| GitLab CI | [`examples/gitlab-ci.yml`](examples/gitlab-ci.yml) |
| Bitbucket Pipelines | [`examples/bitbucket-pipelines.yml`](examples/bitbucket-pipelines.yml) |
| 自托管 Git (pre-receive hook) | [`examples/pre-receive`](examples/pre-receive) |
## CI/CD 集成(手动)
如果您倾向于直接安装二进制文件:
```
- name: Check for evil merges
run: |
go install github.com/fimskiy/evil-merge-detector/cmd/evilmerge@latest
evilmerge scan --branch=main --fail-on=warning
```
## 标志
| 标志 | 描述 | 默认值 |
|------|-------------|---------|
| `--branch` | 要扫描的分支 | 当前 HEAD |
| `--since` | 扫描此日期之后的提交 (YYYY-MM-DD) | — |
| `--until` | 扫描此日期之前的提交 (YYYY-MM-DD) | — |
| `--since-tag` | 扫描此标签之后的提交 | — |
| `--until-tag` | 扫描此标签之前的提交 | — |
| `--severity` | 报告的最低严重级别:`info`、`warning`、`critical` | `info` |
| `--limit` | 要分析的合并提交最大数量 | 无限制 |
| `--format` | 输出格式:`text`、`json`、`sarif` | `text` |
| `--fail-on` | 如果发现达到或超过指定严重级别的结果,则退出码为 1 | — |
| `--commit` | 详细检查特定的合并提交 (哈希值) | — |
| `--timeout` | 最大扫描持续时间,例如 `30s`、`5m` | 无限制 |
| `--ignore-bots` | 跳过已知机器人(dependabot、renovate 等)的合并 | false |
| `--exclude` | 排除匹配此 glob 模式的文件中的发现结果(可重复使用) | — |
| `--include` | 仅报告匹配此 glob 模式的文件中的发现结果(可重复使用) | — |
| `--output` | 将结果写入文件而非标准输出 | — |
| `--workers` | 用于合并分析的并行 worker 数量 | 1 |
| `--verbose` | 将每个已分析的提交打印到标准错误 | false |
## 配置
项目级别的默认值位于仓库根目录的 `.evilmerge.yml` 中。CLI 标志会覆盖文件中的值;`exclude`/`include` 模式是累加的。
```
# .evilmerge.yml
fail-on: warning
ignore-bots: true
exclude:
- "*.lock"
- "dist/**"
include:
- "src/**"
output: results.sarif
```
### 忽略列表
创建 `.evilmerge-ignore` 以永久将特定的提交或作者加入白名单:
```
# 以 # 开头的行是注释
# Commit hashes(7–40 个十六进制字符,支持短前缀)
abc1234
deadbeef12345678
# Author names 或 emails
legacy-bot@company.com
Merge Bot
```
任何类似于十六进制字符串(≥7 个字符)的内容将被视为提交哈希前缀;其他所有内容均被视为作者姓名或电子邮件。
## 工作原理
对于每个具有父提交 **P1** 和 **P2** 的合并提交 **M**:
1. 找到合并基点 **B** = P1 和 P2 的共同祖先
2. 对于 M 中的每个文件,将其内容与 B、P1 和 P2 进行比较
3. 标记出所有 M 的内容无法用任一父提交解释的文件
## 许可证
MIT —— 详见 [LICENSE](LICENSE)
标签:CI/CD安全, DevSecOps, DNS 解析, EVTX分析, Go语言, Llama, StruQ, 上游代理, 云安全监控, 仓库扫描, 代码安全, 代码审查, 代码篡改检测, 后门检测, 安全可观测性, 日志审计, 源代码管理, 漏洞枚举, 版本控制, 程序破解, 网络安全研究, 邪恶合并, 静态分析