Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
sqlite-rtree-rowid0 — SQLite 3.53.4 - High - Local - UAF - rtree last_insert_rowid 0 node hash | Kitploit
Tools/GitHubGitHub/abraxas/sqlite-rtree-rowid0
Dynamic Analysis (Sandboxing)Memory ForensicsVulnerability AnalysisExploitationFuzzingBinary AnalysisPapers & ResearchDatabase Security
GitHubabraxas/sqlite-rtree-rowid0

sqlite-rtree-rowid0

SQLite 3.53.4 - High - Local - UAF - rtree last_insert_rowid 0 node hash

View Repository
96 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - sqlite-rtree-rowid0

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  sqlite-rtree-rowid0

sqlite-rtree-rowid0

Class: UAF Reach: Local

SQLite 3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69, SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc) - Hwaci

nodeWrite hashes a new rtree node with iNode==0 when sqlite3_last_insert_rowid() stays 0 after an INSERT into %_node that still reports OK. nodeHashDelete skips 0. nodeRelease after SplitNode frees the RtreeNode while the hash still holds it. Later nodeHashLookup is a heap use-after-free. Same nodeWrite is on the geopoly path.

Not demonstrated RCE. ASan READ in nodeHashLookup. The later branch-3.53 fix is SQLITE_CORRUPT_VTAB when the assigned node number is still 0. That check is not on this GA.

IDno CVE yet
ClassUAF (heap use-after-free of RtreeNode; not demonstrated RCE)
ReachLocal (untrusted SQL or untrusted .db on an rtree/geopoly table)
CWECWE-416
CVSSHigh: 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
ProductSQLite rtree / geopoly (SQLITE_ENABLE_RTREE)
Affected3.53.4 (b09c88c)
Authattacker SQL or a planted shadow-table trigger / WITHOUT ROWID %_node
LicenseGNU Affero GPL v3.0
Lab127.0.0.1:18890 only. ASan witness. No exploit payload.

What an attacker can do

On an rtree or geopoly table, make node INSERT report OK while last_insert_rowid() stays 0. Documented ways: replace %_node with WITHOUT ROWID, or plant BEFORE INSERT RAISE(IGNORE) on the shadow table, then reopen so the connection's last rowid is 0. INSERT until a node split. The right sibling is hashed as node 0, released, and still findable.

The host process then uses a freed RtreeNode. Lab is AddressSanitizer heap-use-after-free. Instruction-pointer control is not in this pack. The crash is.

SQLITE_VTAB_INNOCUOUS is set, so rtree still runs with trusted_schema off. Default compile does not set SQLITE_DEFAULT_DEFENSIVE. A pre-planted trigger in an untrusted DB file still runs when rtree's own pWriteNode INSERT executes.

How I found it

Twenty source hunts of https://github.com/sqlite/sqlite tag https://github.com/sqlite/sqlite/tree/version-3.53.4. Canonical tree is https://sqlite.org/src. GitHub is a Fossil mirror. 3.54.0 is still a draft. This leftover is typical extra -DSQLITE_ENABLE_RTREE (official recommended compile, Windows nmake OPTS, autoconf fallback, and fuzzcheck all set it).

if( pNode->iNode==0 && rc==SQLITE_OK ){
  pNode->iNode = sqlite3_last_insert_rowid(pRtree->db);
  nodeHashInsert(pRtree, pNode);
}
static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
  RtreeNode **pp;
  if( pNode->iNode!=0 ){
    pp = &pRtree->aHash[nodeHash(pNode->iNode)];
    for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); }
    *pp = pNode->pNext;
    pNode->pNext = 0;
  }
}

nodeAcquire looks up the hash before rejecting iNode<=0. A hit on the freed zero entry is the UAF. A miss on iNode<=0 is SQLITE_CORRUPT_VTAB, which is a different path.

Wrong turns already recorded: treating %_rowid last_insert_rowid 0 as this bug (that assigns cell rowid 0, not the hash UAF); expecting SQLITE_CORRUPT_VTAB on this pin (that is the later fix); filling 50 cells so there is no split; planting the trigger and not reopening; lookaside hiding the free from ASan; calling the crash RCE.

Lab

cd lab
./run.sh

Amalgamation 3.53.4 with -DSQLITE_ENABLE_RTREE=1 and -fsanitize=address. Vendor rtreeI.test 2.0-2.2: fill 51 rows (RTREE_MAXCELLS), BEFORE INSERT RAISE(IGNORE) on %_node, reopen last_insert_rowid()==0, INSERT the 52nd row (split), then SELECT *. Control split without the trigger is OK. Bind 127.0.0.1:18890. Harness is lab/harness.c.

control-split=ok
reopen-last-rowid=0
witness-before-split=SQLITE-RTREE-ROWID0-WITNESS
ERROR: AddressSanitizer: heap-use-after-free
READ of size 8 ... nodeHashLookup
freed by ... nodeRelease / SplitNode
SUCCESS sqlite-rtree-rowid0 how=asan-uaf-nodehash SQLITE-RTREE-ROWID0-WITNESS

The fix

After sqlite3_last_insert_rowid(), if iNode is still 0, return SQLITE_CORRUPT_VTAB and do not nodeHashInsert. branch-3.53 11ce330557 / Git 63b6d705 (2026-09-24) does that. The test expects "database disk image is malformed". This GA does not.

References

  • https://github.com/sqlite/sqlite tag https://github.com/sqlite/sqlite/tree/version-3.53.4 (b09c88c14082339b66c7b7158d609a771e64ca69)
  • Canonical https://sqlite.org/src SOURCE_ID 2026-07-24 19:02:57 bf7c7f30031888f4e796e429ab3978879485813aaca6f641c7b33e4e09459bcc
  • https://github.com/sqlite/sqlite/blob/version-3.53.4/ext/rtree/rtree.c nodeWrite, nodeHashDelete, nodeRelease, nodeAcquire, SplitNode
  • branch-3.53 fix 11ce330557 (2026-09-24, Claude / Ada Logics)
Download Tool