
SQLite 3.53.4 - High - Local - heap OOB write - session changeset same-name nCol growth
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · sqlite-session-ncol
Class: heap OOB write Reach: Local
SQLite 3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69, SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc) with -DSQLITE_ENABLE_SESSION. A two-block changeset that reuses table name t with nCol=2 then nCol=64 skips sessionTableInfo reset (sqlite3session.c:5619) and memsets past the first-block aUpdateMask. ASan WRITE of size 12 in sessionUpdateFind. Control single 2-col UPDATE apply-rc=0.
Not a default amalgamation unless SESSION is on. CVE-2026-50812 NPD is closed on 3.53.2+. Not a weaponized RCE payload. The oracle is the ASan WRITE.
| ID | no CVE yet |
| Class | heap OOB write (ASan WRITE of size 12; not demonstrated RCE) |
| Reach | Local (untrusted changeset via sqlite3changeset_apply*) |
| CWE | CWE-787 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Product | SQLite Session extra (Hwaci) |
| Affected | 3.53.4 (b09c88c) compiled -DSQLITE_ENABLE_SESSION |
| Auth | host applies an untrusted changeset |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18900 only. ASan WRITE-of-size-12 witness. |
Apply an untrusted changeset whose second table block reuses a table name with a larger nCol. Heap OOB write. Compile extra. Not a default amalgamation unless SESSION is on.
The first block allocates aUpdateMask from pIter->nCol. The later same-name block skips sessionTableInfo reset and memsets a larger mask over the old allocation. Lab: nCol=2 then nCol=64 UPDATE. ASan WRITE of size 12 in sessionUpdateFind. Control single 2-col UPDATE apply-rc=0.
Do not treat this pack as a write-what-where gadget. ASan WRITE-of-size-12 is the oracle.
Twenty source hunts of SQLite 3.53.4 after the 3.53.2 FTS5 / session-NPD wave. CVE-2026-50812 is closed (sessionBindRow treats a missing value as SQLITE_CORRUPT). Session still keys SessionApplyCtx on table name only. A second block with the same name and a larger declared column count reuses aUpdateMask.
Wrong turns already recorded: treating the default amalgamation as in-scope (SESSION is off); re-filing CVE-2026-50812; sending one table block with nCol=64 against a 2-col schema (schemaMismatch, no write); claiming RCE from a 12-byte memset.
cd lab
./run.sh
ASan amalgamation from official sqlite-src-3530400 zip. Compile extra -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK. Health on 127.0.0.1:18900. Bind it to loopback.
SUCCESS sqlite-session-ncol how=asan-heap-write-sessionUpdateFind write-size=12 control-apply-rc=0 SQLITE-SESSION-NCOL-WITNESS
When a later changeset table block reuses a name, rebuild SessionApplyCtx the way a new name already does: free aUpdateMask, re-run sessionTableInfo, refuse a larger nCol than the live schema. Trunk 3f57024aec / branch-3.53 a1dd7123d8 (2026-08-17) is after this GA.
b09c88c14082339b66c7b7158d609a771e64ca69)sessionChangesetApply :5619, sessionUpdateFind :4381-4412