
SQLite 3.53.4 - High - Local - Crash - VALUES UNION ALL fallback cleanup stack overflow
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sqlite-values-union
Class: Crash Reach: Local
SQLite 3.53.4 (b09c88c) - Hwaci
Default VALUES uses a co-routine. WITH (or schema reload, or a non-constant row) forces sqlite3MultiValues onto UNION ALL. Compound-SELECT length is skipped when SF_Values is set (parse.y:562-567). A large enough row list is then rejected by SQLITE_LIMIT_EXPR_DEPTH, and recursive sqlite3ExprDeleteNN blows the C stack on the error-cleanup path.
Plain VALUES of 5000 rows is fine. WITH plus 1000 rows errors cleanly (Expression tree is too large). WITH plus 300000 rows is ASan stack-overflow in sqlite3ExprDeleteNN (rc=134). Not RCE.
| ID | no CVE yet |
| Class | Crash (ASan stack-overflow on ExprDelete; not demonstrated RCE) |
| Reach | Local (untrusted SQL, or VALUES inside VIEW/TRIGGER) |
| CWE | CWE-674 |
| CVSS | High: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| Product | SQLite |
| Affected | 3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69, SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc). Leftover of later trunk VALUES compound cap. |
| Auth | attacker SQL, or a planted schema that takes the UNION ALL fallback |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18820 only. ASan amalgamation. Crash witness. |
Feed untrusted SQL that a host will prepare. Prefix a huge VALUES list with WITH so the co-routine path is off. The parse is supposed to fail with an expression-depth error. Cleanup of that tree recurses in sqlite3ExprDeleteNN until the process dies.
Same fallback fires when VALUES lives in a VIEW or TRIGGER (db->init.busy). The host is the embedder: a CLI, an app that prepares attacker SQL, a service that opens a hostile .db. SQLite does not eval the VALUES bytes as code. The crash is the finding.
Twenty source hunts of github.com/sqlite/sqlite tag version-3.53.4. Skip list already closed CVE-2026-11824, session NPD, concat_ws, LOOKASIDE, JSON UAF, WAL-reset. Default load_extension is off. Parser/VDBE leftover was this VALUES UNION ALL skip plus a recursive destructor.
if( (p->selFlags & (SF_MultiValue|SF_Values))==0
&& (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
&& cnt>mxSelect
){
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
}
if( pParse->bHasWith
|| pParse->db->init.busy
|| exprListIsConstant(pParse,pRow)==0
...
){
/* The co-routine method cannot be used. Fall back to UNION ALL. */
...
pSelect->op = TK_ALL;
pSelect->pPrior = pLeft;
}
clearSelect() walks pPrior iteratively. sqlite3ExprDeleteNN() still recurses on pRight and on pLeft when EP_Static is set.
Wrong turns: 1000 rows with WITH error cleanly at the documented depth cap and do not crash; needed 300000 rows so destructor depth blows the 8 MiB C stack. Plain VALUES stays on the co-routine and is the negative control.
cd lab
./run.sh
Canonical 3.53.4 source zip, ASan sqlite3. Compose sqlite-values-union. Published 127.0.0.1:18820. Bind it to loopback.
SUCCESS sqlite-values-union how=with-values-union-all-fallback-exprdelete rows=300000 crash=asan-stack-overflow plain=5000 depth-error=1000 SQLITE-VALUES-UNION-WITNESS
Apply SQLITE_LIMIT_COMPOUND_SELECT to VALUES the same way other compounds are capped. Walk the UNION ALL chain iteratively on delete, or cap EXPR_DEPTH before the tree is built so cleanup cannot recurse off the C stack. Later trunk (Bug 2026-10-04T05:34:47Z) is after this GA.
b09c88c14082339b66c7b7158d609a771e64ca69)2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bccsrc/parse.y:562-567 compound-SELECT skip when SF_Values is setsrc/insert.c:681-704 sqlite3MultiValues UNION ALL fallbacksrc/expr.c:1406-1430 recursive sqlite3ExprDeleteNN