
SQLite 3.53.4 - High - Local - Crash - COLLATE chain skips SQLITE_LIMIT_EXPR_DEPTH
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sqlite-collate-depth
Class: Crash Reach: Local
SQLite 3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69, SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc) - Hwaci
The COLLATE grammar action never calls sqlite3ExprCheckHeight. sqlite3ExprAddCollateToken allocates a TK_COLLATE node with nHeight still 1, then hangs the prior expression off pLeft. Ordinary operators go through sqlite3PExpr and get the documented SQLITE_LIMIT_EXPR_DEPTH (default 1000). This operator does not.
The walker still recurses on every pLeft. EP_Skip is for affinity, not for sqlite3WalkExprNN. A 50-node chain returns 1. So do 8k and 40k, past the depth limit. 120k ASan stack-overflows in sqlite3WalkExprNN (rc=134). Not RCE.
Canonical tree is https://sqlite.org/src. GitHub sqlite/sqlite is a Fossil mirror. Official zip sqlite-src-3530400. Public domain library. This pack is AGPLv3.
| ID | no CVE yet |
| Class | Crash (ASan stack-overflow in sqlite3WalkExprNN; not demonstrated RCE) |
| Reach | Local (untrusted SQL or a planted VIEW) |
| CWE | CWE-674, CWE-770 |
| 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 3.53.4 |
| Affected | 3.53.4 (b09c88c); leftover of later trunk COLLATE height check |
| Auth | untrusted SQL or VIEW; default load_extension stays off |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18800 only. ASan amalgamation. Crash witness. |
Feed a long postfix COLLATE BINARY chain as SQL, or plant it in a VIEW inside an untrusted .db. The host process walks the chain and dies on the C stack. The documented expression-depth limit never runs on this operator.
SELECT 1 COLLATE BINARY COLLATE BINARY ... is enough. Same shape in CREATE VIEW v AS SELECT 1 COLLATE BINARY ... then SELECT * FROM v on a fresh connection. Default SQLITE_LIMIT_SQL_LENGTH (1e9) holds the ~1.8 MB chain that overflowed an 8 MB stack in this lab.
This is a crash of the embedder process. It is not instruction-pointer control. load_extension stays off.
Twenty source hunts of SQLite tag version-3.53.4 after OpenLiteSpeed. Latest GA, not the 3.54.0 draft. sqlite.org/security.html treats untrusted SQL and untrusted .db as first-class. Default load_extension is off.
parse.y for COLLATE is three lines:
expr(A) ::= expr(A) COLLATE ids(C). {
A = sqlite3ExprAddCollateToken(pParse, A, &C, 1);
}
sqlite3ExprAddCollateToken sets pNew->pLeft = pExpr and EP_Collate|EP_Skip. sqlite3ExprAlloc left nHeight = 1. No sqlite3ExprCheckHeight. sqlite3PExpr does both of those things for every other binary operator.
Wrong turns: treating 8k COLLATE as the crash (it returned 1); treating 40k as the crash (it also returned 1, well past SQLITE_LIMIT_EXPR_DEPTH 1000); needing 120k before ASan died in sqlite3WalkExprNN.
This is G1 of fourteen leftovers on the pin. Siblings are other posts.
cd lab
./run.sh
ASan amalgamation from official sqlite-src-3530400 (fallback clone of tag version-3.53.4). Compose sqlite-collate-depth. Dummy HTTP on 127.0.0.1:18800. Bind it to loopback.
SUCCESS sqlite-collate-depth how=asan-stack-overflow control=50 crash-n=120000 SQLITE-COLLATE-DEPTH-WITNESS
50 COLLATE returns 1. 8k and 40k also return 1. 120k dies rc=134, ASan stack-overflow in sqlite3WalkExprNN. Pin check is SELECT sqlite_version() / SELECT sqlite_source_id().
Call sqlite3ExprCheckHeight on the COLLATE node after attaching pLeft, the way sqlite3PExpr already does. Recompute nHeight from the child. A postfix operator is still an expression tree.
Trunk 252c0b7bf5 (2026-10-04) is after this GA.
b09c88c14082339b66c7b7158d609a771e64ca69)src/parse.y COLLATE actionsrc/expr.c sqlite3ExprAddCollateToken, sqlite3ExprAlloc (nHeight = 1), sqlite3PExpr / sqlite3ExprCheckHeightsrc/walker.c sqlite3WalkExprNNsrc/sqliteLimit.h SQLITE_MAX_EXPR_DEPTH default 1000