extratao/CVE-2026-51302-PoC
GitHub: extratao/CVE-2026-51302-PoC
通过源码分析和 Git 历史溯源,证明 CVE-2026-51302 是一个由 LLM 幻觉生成的虚假 SQLite 漏洞报告。
Stars: 0 | Forks: 0
# CVE-2026-51302:技术上的自相矛盾
*抱歉起了这个标题党仓库名,但这个 CVE 完完全全就是 LLM 幻觉生成的垃圾内容,看到 CNA 在各项声明如此前后矛盾的情况下居然还会采纳,确实挺让人伤心的 💔*
## 结论
CVE-2026-51302 根本不存在 😱
公布的 SQL 语句在 AddressSanitizer 环境下,无法在任何 SQLite 3.41 版本中复现 use-after-free。更重要的是,声明中所指出的根本原因与受影响的源码完全不符:
- SQLite 3.41.0、3.41.1 或 3.41.2 中根本不存在 `exprComputeOperands()` 函数;
- 该函数于 2025 年 6 月 30 日才被引入,比 SQLite 3.41 晚了两年多;
- `regFree1` 是一个整型的虚拟机寄存器标识符,而不是一个指向堆存储的指针;
- `sqlite3ReleaseTempReg()` 只是让一个寄存器可供重用,并不会在 `regFree1` 中留下悬空的 C 指针;
- 在包含 `exprComputeOperands()` 函数的源码版本中,操作数会在临时寄存器被释放之前进行计算,这与安全公告中声明的顺序截然相反;而且
- 公布的 SQL 不包含任何子查询操作数,因此根本没有触发引入 `exprComputeOperands()` 所针对的优化逻辑。
这个 CVE 记录应当被驳回,我将向 MITRE 提出 CNA 争议申诉 😉
## 安全公告的声明
该公告将受影响的版本标示为“SQLite 3.41”,并提供了以下查询语句:
```
SELECT CASE WHEN (1+3) THEN (5*8) ELSE (2/0) END FROM test;
```
其中声称:
1. `sqlite3ReleaseTempReg()` 释放了与 `regFree1` 关联的堆内存;
2. `regFree1` 作为悬空引用保留了下来;
3. 随后 `exprComputeOperands()` 访问了已释放的内存;且
4. 针对 ASan 构建版本运行该查询会产生明显的 heap-use-after-free 堆栈追踪。
## 源码分析
### SQLite 3.41 中的 sqlite3ReleaseTempReg()
SQLite 3.41.0 的合并源码文件对该函数的定义如下:
```
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
if( iReg ){
sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
if( pParse->nTempRegaTempReg) ){
pParse->aTempReg[pParse->nTempReg++] = iReg;
}
}
}
```
该函数接收 `iReg` 作为 `int` 类型。它会将该整数记录在 `pParse->aTempReg` 中,以便该寄存器编号可以被再次分配:
```
SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){
if( pParse->nTempReg==0 ){
return ++pParse->nMem;
}
return pParse->aTempReg[--pParse->nTempReg];
}
```
这是 VDBE 程序生成过程中的寄存器生命周期管理。该公告将 `regFree1` 描述为指向已释放堆存储的存活指针。但事实并非如此:
```
int regFree1 = 0, regFree2 = 0;
int r1, r2;
r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1);
r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2);
codeCompare(pParse, pL, pR, opx, r1, r2, addrDone, p5, isCommuted);
sqlite3ReleaseTempReg(pParse, regFree1);
sqlite3ReleaseTempReg(pParse, regFree2);
```
生成的比较操作会在寄存器标识符被释放以供重用之前消耗掉它们。
### exprComputeOperands() 根本不存在
对 Git 镜像进行溯源搜索后发现,`exprComputeOperands()` 是由以下提交引入的:
```
e24f20a4f5a6d26cdaece58eff77619a4ee757b9
2025-06-30T10:30:47Z
Factor out the code that tries to avoid evaluating subquery operands if the other operand is NULL into a subroutine, so that it can be more easily reused by other parts of the code generator.
```
官方的三个 SQLite 3.41 合并源码版本中均不存在该函数。SQLite 3.41 中的漏洞不可能沿着一条在 2025 年才引入的函数执行路径发生,不是吧 MITRE 真的吗? 🥲
### 声明的执行顺序完全颠倒
在现代 SQLite 源码中,`sqlite3ExprIfTrue()` 内部简化的调用顺序如下:
```
addrIsNull = exprComputeOperands(
pParse, pExpr, &r1, &r2, ®Free1, ®Free2);
codeCompare(
pParse, pExpr->pLeft, pExpr->pRight, op,
r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr, EP_Commuted));
/* Other switch cases and generated-bytecode handling occur here. */
sqlite3ReleaseTempReg(pParse, regFree1);
sqlite3ReleaseTempReg(pParse, regFree2);
```
`exprComputeOperands()` 生成寄存器标识符。调用者消耗它们,然后将其释放。而公告却声称 `sqlite3ReleaseTempReg()` 先执行,随后 `exprComputeOperands()` 再去访问已释放的对象。
### 公布的查询语句与现代函数不匹配
引入 `exprComputeOperands()` 的初衷是为了在另一个操作数为 `NULL` 时,避免去计算开销高昂的子查询操作数。而公布的表达式:
```
CASE WHEN (1+3) THEN (5*8) ELSE (2/0) END
```
虽然包含算术运算和 `CASE` 表达式,但并不包含任何子查询操作数。对该查询给出的理由与该函数的调用条件并不相符。
## 补充内容
### 环境
顺便提一下,这是虚拟机信息:
```
Debian GNU/Linux 13 (trixie)
Clang 19.1.7
AddressSanitizer enabled
Optimisation level: -O1
Frame pointers retained
Sanitizer recovery disabled
```
合并源码版本的 SHA:
```
3.41.0 146ce189b67fdbefbf2d72cdc81e198d07ff643614cc9102e9bf063255e8e7e1
3.41.1 df0d54bf246521360c8148f64e7e5ad07a4665b4f902339e844f4c493d535ff5
3.41.2 01df06a84803c1ab4d62c64e995b151b2dbcf5dbc93bbc5eee213cb18225d987
3.53.3 646421e12aac110282ef8cc68f1a62d4bb15fc7b8f09da0b53e29ee690500431
```
### 相关链接汇总 😁
- 公开的安全公告:
- CVE 记录:
- SQLite 发布历史:
- SQLite 3.41.0 发布说明:
- SQLite 3.41.1 发布说明:
- SQLite 3.41.2 发布说明:
- 函数引入记录:
标签:CVE, SQLite, 数字签名, 漏洞分析, 网络安全研究, 路径探测