ShovalBenjer/protobuf-fuzz-guard
GitHub: ShovalBenjer/protobuf-fuzz-guard
一款 Protobuf schema 安全扫描与多语言 fuzz harness 自动生成工具,能在开发阶段检测递归和嵌套类漏洞模式并支持 CI 门禁集成。
Stars: 1 | Forks: 0
# protobuf-fuzz-guard
在攻击者之前发现 protobuf schema 漏洞,并通过一条命令将每个
message 转化为跨四种语言的持续 fuzz 活动。
```
× Recursive message reference: Tree.left references itself. Vulnerable to
│ unbounded recursion attacks.
╭─[service.proto:5:5]
4 │ string value = 1;
5 │ Tree left = 2;
· ───────┬──────
· ╰── here
6 │ Tree right = 3;
╰────
help: Unbounded stack recursion via deeply nested messages
```
## 为什么这很重要
Protobuf 解析器在所有语言中都存在相同的漏洞类别。
此工具会根据主要安全公告中记录的三种漏洞类别检查您的 schema:
| 安全公告 | Runtime | 类别 | 修复版本 |
| --- | --- | --- | --- |
| CVE-2024-7254 (CVSS 8.7) | protobuf-java, protobuf-kotlin, JRuby | 解析嵌套 group 作为 unknown field 时的 Stack overflow | 3.25.5, 4.27.5, 4.28.2 |
| RUSTSEC-2020-0002 (CVE-2020-35858, CVSS 9.8) | Rust prost | 解码深度嵌套输入时的 Stack overflow | prost 0.6.1 |
| RUSTSEC-2024-0437 (CVE-2025-53605) | Rust protobuf | `skip_group` 中不受控的递归 | rust-protobuf 3.7.2 |
## 您将获得什么
- 能够指出确切字段和行的源码跨度诊断信息,通过
`miette` 渲染。
- 通过单条命令生成四种语言的 fuzz harness。
- 基于上述三项安全公告的漏洞目录。
- JSON 输出以及在发现严重问题时返回 `1` 的退出代码,从而使 `protofuzz scan`
能够独立作为 CI 的门禁。
- 单个静态二进制文件。无需 runtime,无需网络访问,且依赖树已在 CI 中通过
`cargo-audit` 和 `cargo-deny` 进行审计。
## 安装
```
cargo build --release --locked
./target/release/protofuzz --help
```
## 扫描 schema
```
protofuzz scan path/to/service.proto
```
诊断信息将输出到 stderr。添加 `--json` 可在
stdout 获取机器可读的检测结果:
```
protofuzz scan --json path/to/service.proto
```
以此为 pipeline 设置门禁。当存在任何严重检测结果时,
该命令将以 `1` 退出:
```
protofuzz scan proto/**/*.proto
```
## 生成 harness
一条命令即可将每个 message 的 harness 写入到 `fuzz_harnesses//`。传入
`-l` 来选择语言:
```
protofuzz generate service.proto -l rust -l go -o out/
```
## 立即尝试
将以下内容保存为 `tree.proto`:
```
syntax = "proto3";
message Tree {
string value = 1;
Tree left = 2;
Tree right = 3;
group Legacy = 4;
}
```
扫描它:
```
protofuzz scan tree.proto
```
您将获得三个严重检测结果,每一个都会在其源码位置高亮显示:
两个递归引用以及已弃用的 `group` field。退出代码为 `1`。
## 检测规则
| 规则 | 严重程度 | 模式 |
| --- | --- | --- |
| Message 嵌套深度达到 5 或以上 | critical | `PROTOBUF-RECURSION-PROTO2` |
| Message 嵌套深度在 3 到 4 之间 | warning | none |
| 直接递归 message 引用 | critical | `PROTOBUF-RECURSION-PROTO2` |
| `group` 或 `TYPE_GROUP` field | critical | `CVE-2024-7254-CLASS` |
| 重复的嵌套 message | warning | none |
| 三个或更多重复的 `bytes` field | warning | `PROTOBUF-UNKNOWN-FIELD-OVERFLOW` |
## 生成的 Rust harness
Rust 目标使用 `prost` 进行解码并执行往返测试。`prost` 默认通过
`DecodeContext` 强制执行 100 的递归限制,因此除非启用了
`no-recursion-limit`,否则该 harness 自带 DoS 保护。
```
#![no_main]
use libfuzzer_sys::fuzz_target;
use prost::Message;
use acme_v1::Person;
fuzz_target!(|data: &[u8]| {
if let Ok(msg) = Person::decode(data) {
let mut buf = Vec::with_capacity(msg.encoded_len());
msg.encode(&mut buf)
.expect("re-encoding a successfully decoded message is infallible");
let _ = Person::decode(buf.as_slice());
}
});
```
## 开发
```
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo nextest run --workspace
```
CI 会运行 `rustfmt`、拒绝警告的 `clippy`、`nextest`、`cargo-audit`、
`cargo-deny` 以及 nightly 版本的 fuzz 冒烟测试。Fuzz 相关代码位于
[`fuzz/`](fuzz/README.md) 并且需要 nightly 工具链。供应链策略位于
[`deny.toml`](deny.toml)。
## 目录结构
```
crates/pfg-core/ Library: span-aware parser, scanner, harness generator
crates/protofuzz-cli/ The protofuzz binary, built on clap
fuzz/ cargo-fuzz targets that self-test the scanner
docs/ Research report and migration plan
legacy/ Original Python implementation, kept for reference
```
## 许可证
MIT
标签:可视化界面, 通知系统