msuiche/gguf_cve2026_7482
GitHub: msuiche/gguf_cve2026_7482
针对 Ollama CVE-2026-7482 堆越界读取漏洞的 POC 生成与恶意 GGUF 模型文件检测工具集,帮助安全研究人员和运维人员验证并排查该高危漏洞的利用风险。
Stars: 0 | Forks: 0
# CVE-2026-7482 (Bleeding Llama) 检测工具
用于检测严重的 Ollama 堆越界读取漏洞 (CVSS 9.1) 的安全研究工具。
## 背景
CVE-2026-7482 是 Ollama 0.17.1 之前版本中存在的一个未经身份验证的堆越界读取漏洞。当恶意 GGUF 模型文件通过 `/api/create` 并使用 `quantize=F32` 进行处理时,量化路径会读取超出源缓冲区末尾的内容,将进程内存(环境变量、API 密钥、用户聊天记录)泄漏到输出模型中。
**攻击向量:** 攻击者上传恶意 GGUF → 携带 `quantize=F32` 的 `/api/create` → `ConvertToF32` 越界读取 → 通过 `/api/push` 窃取数据
**受影响范围:** 约 300,000 台以 `OLLAMA_HOST=0.0.0.0` 配置暴露在公网的 Ollama 服务器
**修复方案:** 升级至 Ollama 0.17.1+
## POC 生成器: `gguf_cve2026_7482_poc.py`
生成 4 个演示不同利用模式的恶意 GGUF 文件:
| 文件 | 张量 | 声明大小 | 实际大小 | 越界窗口 | 类型 |
|------|--------|----------|--------|------------|------|
| `poc_basic_shape_mismatch.gguf` | token_embd.weight | 1,024 B | 128 B | 896 B | 基础不匹配 |
| `poc_bleeding_llama.gguf` | blk.0.attn_q.weight | 8,192 B | 256 B | 7,936 B | 完整攻击链 |
| `poc_multi_tensor.gguf` | blk.0.ffn_up.weight | 16,384 B | 512 B | 15,360 B | 隐藏于合法张量中 |
| `poc_offset_overlap.gguf` | tensor_b | 8,192 B | 1,536 B | 6,656 B | 偏移重叠变体 |
```
python3 gguf_cve2026_7482_poc.py
```
## 检测工具: `gguf_cve2026_7482_detector.py`
包含 6 条规则检测引擎的完整 GGUF v3 解析器。用于分析任何 GGUF 文件中可能表明存在利用尝试或文件损坏的结构异常。
### 使用方法
```
# 单文件详细报告
python3 gguf_cve2026_7482_detector.py model.gguf
# 多文件快速扫描
python3 gguf_cve2026_7482_detector.py *.gguf --quiet
# 用于 CI/CD 集成的 JSON 输出
python3 gguf_cve2026_7482_detector.py model.gguf --json -o report.json
```
### 检测规则说明
#### SHAPE_MISMATCH (严重)
**定义:** 张量的声明大小(shape × type_size)大于实际由文件支撑的可用数据。
**触发原因:** 这是 CVE-2026-7482 的主要触发条件。元数据声称“此张量包含 X 字节”,但文件实际仅包含 Y 字节。当 Ollama 的量化代码执行 F16→F32 转换时,它信任 shape 并尝试从 Y 字节的缓冲区中读取 X 字节,从而越界读取到堆内存中。
**示例:** 某张量声明 shape=[4096],类型为 F16 = 8,192 字节,但在该张量的偏移量之后,文件仅包含 256 字节。剩余的 7,936 字节将是未初始化的堆内存。
**安全影响:** 在受影响的 Ollama 版本中,这是导致内存泄漏的直接漏洞利用路径。
#### EXCEEDS_FILE (严重/高)
**定义:** 张量的绝对结束位置(data_offset + tensor_offset + declared_size)超出了文件的末尾。
**触发原因:** 张量声明的范围在物理上无法容纳在该文件中。这是 SHAPE_MISMATCH 的一种更强形式,它考虑了绝对定位。
**示例:** 文件总大小为 1,000 字节。位于偏移量 900 处的张量声明了 1,024 字节的数据。结束位置 = 1,924 > 1,000。
**安全影响:** 与 SHAPE_MISMATCH 结合出现时,可确认可利用性。单独出现时,表明存在严重的结构损坏。
#### OFFSET_OVERLAP (高)
**定义:** 两个张量声明的范围彼此重叠。
**触发原因:** 在有效的 GGUF 文件中,张量数据区域不应重叠。范围重叠表明该文件是手动构造的或已损坏。ggml C++ 加载器会明确拒绝非单调偏移(ggml C++ 加载器第 747 行的 gguf.cpp),但 Ollama 的 Go 重写版可能未执行此检查。
**示例:** 张量 A 位于偏移量 0,声明 1,024 字节。张量 B 位于偏移量 512,声明 1,024 字节。512-1023 字节同时被两者占用。
**安全影响:** 可能导致加载器出现未定义行为的结构异常。可能表明存在篡改。
#### NON_MONOTONIC_OFFSET (中)
**定义:** 张量偏移量未按严格递增顺序排列。
**触发原因:** GGUF 格式期望张量按顺序存储。较后出现的张量如果具有比较早张量更小的偏移量,则违反了这一假设。ggml C++ 加载器检查 `ti.offset != ctx->size` 以强制执行顺序布局。
**示例:** 张量 0 的偏移量为 1000,张量 1 的偏移量为 500。这是非单调的。
**安全影响:** 表明文件结构被篡改。可能导致某些加载器出现解析错误或关联到错误的张量数据。
#### ZERO_DIMENSION (高)
**定义:** 张量的某个维度值为零。
**触发原因:** 零维度使得张量在数学上无效(零个元素)。虽然在某些极端情况下技术上可能存在,但这通常是元数据损坏或故意格式错误文件的迹象。
**示例:** Shape = [768, 0, 768] → 768 × 0 × 768 = 0 个元素,但元数据可能仍会声明一个非零的字节大小。
**安全影响:** 无效张量可能导致下游消费者出现除以零、分配问题或解析失败。
#### INVALID_BLOCK_ALIGNMENT (高)
**定义:** 量化块类型的张量(如 Q4_0、Q4_K 等)的元素数量不能被其块大小整除。
**触发原因:** 块量化类型要求将元素组织成固定大小的块。例如,Q4_0 使用 32 元素的块。具有 100 个元素的张量无法编码为 Q4_0 (100 % 32 != 0)。
**示例:** 声明为 Q4_K(块大小为 256)的 1,000 个元素。1000 % 256 = 232 ≠ 0。
**安全影响:** 表明量化元数据格式错误。解码将失败或产生不正确的结果。
### 输出示例
**静默模式:**
```
CRITICAL bleeding-llama.gguf (1 critical, 0 high, 1 tensors)
SAFE legitimate-model.gguf (0 critical, 0 high, 287 tensors)
```
**JSON 输出结构:**
```
{
"filepath": "model.gguf",
"overall_risk": "CRITICAL",
"cve_2026_7482_vulnerable": true,
"summary": {"critical": 1, "high": 0, "total_tensors": 1},
"tensors": [...],
"findings": [...]
}
```
## 技术细节
### 为什么 ggml C++ 是安全的,而 Ollama Go 存在漏洞
ggml C++ 加载器维护了一个根据真实文件长度初始化的 `nbytes_remain` 不变量。每次通过 `gguf_reader::read()` 的读取都会对照此计数器进行检查,如果耗尽则会干净地失败。批量张量读取 `gr.read(data->data, ctx->size)` 完全无法读取超过 EOF 的内容。
Ollama 的 Go 重写版使用 `io.SectionReader`,它会静默地将读取操作限制在 EOF 范围内。当代码基于声明的元数据预分配缓冲区,然后执行无限读取时,缓冲区中未读取的部分将保持未初始化状态,包含堆上先前存在的任何内容(环境变量、API 密钥、其他用户数据)。
### GGUF 格式结构
```
+--------+----------+-------------------+
| Header | Metadata | Tensor Info Array |
+--------+----------+-------------------+
|
v
(padding to alignment)
|
v
+-------------------------------------+
| Tensor Data Blob |
+-------------------------------------+
```
该漏洞之所以存在,是因为张量元数据(shape、type、offset)在被用于缓冲区分配和复制之前,没有根据实际的文件大小进行验证。
## 参考文献
- [CVE-2026-7482 - cvefeed.io](https://cvefeed.io/vuln/detail/CVE-2026-7482)
- [Bleeding Llama - Cyera Research](https://www.cyera.com/research/bleeding-llama-critical-unauthenticated-memory-leak-in-ollama)
- [NYU Shanghai RITS - Bleeding Llama](https://rits.shanghai.nyu.edu/ai/bleeding-llama-critical-unauthenticated-memory-leak-hits-300000-ollama-servers)
- [Ollama 安全公告](https://github.com/ollama/ollama/security)
标签:AI风险缓解, API密钥泄露, Bleeding Llama, CI/CD安全集成, CISA项目, CVE-2026-7482, CVSS 9.1, GGUF模型, GGUF解析器, HTTP工具, Ollama漏洞, OOB Read, PoC生成器, Python安全工具, XXE攻击, 内存泄露, 堆越界读取, 大语言模型安全, 安全防护, 数据窃取, 无服务器架构, 机密管理, 模型文件安全, 漏洞检测工具, 环境变量泄露, 网络安全审计, 网络边界安全, 逆向工具, 量化漏洞