## https://sploitus.com/exploit?id=A820751A-E413-589A-97E0-4BAD8D4D0CB3
# CVE-2026-39113: Heap Buffer Overflow in SQLite's Optional SQLAR Extension
## Executive Summary
CVE-2026-39113 is a heap buffer overflow in SQLite's optional SQLAR extension. In an application that has loaded the extension, an attacker who can invoke `sqlar_uncompress()` with a controlled compressed blob and size can cause zlib to write beyond a heap allocation on an LP64 system. This is a memory-safety boundary failure inside the host process; it is not a SQLite database-file parsing issue, an authentication bypass, or a flaw reachable in every default SQLite deployment.
The vulnerable behavior was introduced on 2026-03-11 by Git commit [`169f68e`](https://github.com/sqlite/sqlite/commit/169f68ed88b34cb68f720191c64c058f2ccec508) (Fossil check-in `8bdc0d485e3ad0c7...`) and corrected on 2026-04-01 by Git commit [`34e139d`](https://github.com/sqlite/sqlite/commit/34e139d3a306fcc0eeaf29de69783a311d48356b) (Fossil check-in `6194f3b5314ef98b...`). The affected scope is source snapshots and custom builds from `169f68e` through the parent of `34e139d`. No official SQLite release was verified vulnerable: SQLite 3.52.0 predates the introduction, and SQLite 3.53.0 contains both the introducing change and the fix. SQLite 3.53.0 is therefore the first official release containing the corrected code, not an affected release.
I reviewed the exact vulnerable revision, the introducing and fixing changes, and the 3.52.0 and 3.53.0 release snapshots. I also inspected the preserved output from an authorised run in a disposable WSL2 Ubuntu 24.04 environment. AddressSanitizer observed a heap-buffer-overflow followed by process termination, establishing native heap corruption and denial of service. Code execution was not demonstrated.
## Background
[SQLAR](https://sqlite.org/sqlar.html) is an SQLite archive format. The optional extension in `ext/misc/sqlar.c` registers `sqlar_compress()` and `sqlar_uncompress()` as SQL functions. It is not part of every application using SQLite; the vulnerable path requires the extension to be present and loaded.
For this report, Mallory controls the blob and `SZ` arguments supplied to:
```sql
SELECT sqlar_uncompress(?1, ?2);
```
The tested environment had a 32-bit `int` and 64-bit `sqlite3_int64` and zlib `uLongf`. The function should allocate at least as much memory as zlib is permitted to write. Instead, the vulnerable source converts the 64-bit size to the 32-bit parameter type of `sqlite3_malloc()` while retaining the full value for `uncompress()`.
The vulnerable source snapshot printed `Configuring SQLite version 3.53.0` during configuration. That development-version string must not be confused with the official SQLite 3.53.0 release dated 2026-04-09, whose source contains the fix.
## Vulnerability Details
At the assessed revision, `sqlarUncompressFunc()` in `ext/misc/sqlar.c` reads the attacker-controlled size as a 64-bit integer:
```c
sqlite3_int64 sz;
sz = sqlite3_value_int64(argv[1]);
```
If `sz` is positive and differs from the input blob length, the same value is used in two incompatible ways:
```c
uLongf szf = sz;
const Bytef *pData = sqlite3_value_blob(argv[0]);
Bytef *pOut = sqlite3_malloc(sz);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
sqlite3_result_error(context, "error in uncompress()", -1);
}
```
At this revision, SQLite declares `sqlite3_malloc(int)`. On the tested LP64 build, the PoC value `4294967328` (`0x100000020`) became `32` when passed to that API, while `szf` retained the full 64-bit value. SQLite therefore made a small allocation, but zlib was told that the output buffer could hold more than 4 GiB. Decompressing a 42-byte blob representing 4096 bytes of data then crossed the allocation boundary.
The mismatch entered the project when the 2026-03-11 change replaced `sqlite3_value_int()` with `sqlite3_value_int64()` without changing the allocation API. Source review of SQLite 3.52.0 shows the earlier 32-bit read, so the full-width/short-allocation mismatch was not present there. The 2026-04-01 fix changed the allocation to `sqlite3_malloc64(sz)`. Source review of the official 3.53.0 tag confirms that corrected call.
## Exploitability Analysis
The demonstrated primitive is an out-of-bounds heap write in the process hosting SQLite. The preserved run shows AddressSanitizer detecting the first invalid one-byte write immediately after a 40-byte heap region allocated through `sqlite3_malloc()`, followed by an abort. This directly supports process crash and denial of service.
Exploitation requires all of the following:
- the optional SQLAR extension is loaded;
- Mallory can invoke `sqlar_uncompress()` with a controlled blob and `SZ` value;
- `int` is 32 bits while `sqlite3_int64` and zlib `uLongf` are 64 bits; and
- the narrowed allocation succeeds, allowing zlib to begin decompression.
The PoC controls the decompressed bytes, which is relevant to the severity of native heap corruption. However, turning this primitive into code execution would depend on allocator layout, surrounding process state, mitigations, and a suitable application-level route. No such chain was tested or demonstrated, so this report does not claim code execution.
The preserved run did not include a runtime negative control against the fixed revision. Two source-level controls narrow the explanation: SQLite 3.52.0 reads the size with the 32-bit API, and the official 3.53.0 source allocates with `sqlite3_malloc64()`. These checks support the identified introduction and fix but are not presented as executed fixed-target tests. The prevalence of applications loading this optional extension is unknown.
## Proof of Concept
The repository includes:
- `poc/verify_sqlar_poc.c`, which creates a 4096-byte payload, compresses it, loads `sqlar.so`, and binds `SZ = 4294967328`;
- `poc/reproduce.sh`, which clones pinned SQLite and zlib revisions, builds them with AddressSanitizer, compiles the extension and harness, and runs the trigger; and
- `evidence/asan-summary.txt`, a path-normalized summary of the observed authorised run.
Run the reproducer only in a disposable Linux or WSL environment. It intentionally triggers memory corruption and an AddressSanitizer abort. The script requires `git`, `make`, a C compiler, standard build tools, and network access:
```sh
chmod +x poc/reproduce.sh
./poc/reproduce.sh
```
The reproducer was run again on 2026-08-21 on Ubuntu 24.04 under WSL2 and produced the same AddressSanitizer finding. Its relevant output was:
```text
env: sizeof(int)=4 sizeof(sqlite3_int64)=8 sizeof(uLongf)=8
payload: plain=4096 compressed=42 evil_sz=4294967328 low32=32
ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 1
#0 inflate_fast zlib/inffast.c:252
#4 uncompress zlib/uncompr.c:100
#5 sqlarUncompressFunc sqlite/ext/misc/sqlar.c:97
The write occurred immediately after a 40-byte heap region.
SUMMARY: AddressSanitizer: heap-buffer-overflow in inflate_fast
ABORTING
PoC exit status: 1
```
This output shows the incompatible type widths and crafted size, the zlib write, the call from `sqlarUncompressFunc()`, and the allocation boundary violation. The reproduction script deletes its temporary build directory on exit unless `KEEP_BUILD=1` is set.
## Remediation
Upstream corrected the vulnerable allocation in commit [`34e139d`](https://github.com/sqlite/sqlite/commit/34e139d3a306fcc0eeaf29de69783a311d48356b):
```diff
- Bytef *pOut = sqlite3_malloc(sz);
+ Bytef *pOut = sqlite3_malloc64(sz);
```
This keeps the allocation width consistent with the positive 64-bit `sz` value retained in `uLongf szf` and passed to zlib. The corrected code is present in official SQLite 3.53.0. Users of source snapshots or custom builds containing the vulnerable interval should update to `34e139d` or later. Applications that do not require SQLAR should avoid loading the extension, and applications that do use it should prevent untrusted callers from supplying arbitrary arguments to `sqlar_uncompress()`.
A focused regression test should exercise the SQL function with a valid compressed blob and an `SZ` value above `INT_MAX` whose low 32 bits are small. It should verify that the fixed build does not perform a truncated allocation and should retain ordinary successful decompression and invalid-input error cases as controls.
## Summary
CVE-2026-39113 affects only SQLite source snapshots and custom builds from `169f68e` through the parent of `34e139d` when the optional SQLAR extension is loaded and attacker-controlled calls reach `sqlar_uncompress()` on an LP64 build. A 64-bit size was narrowed by `sqlite3_malloc(int)` while zlib retained the full value, producing an AddressSanitizer-confirmed heap-buffer-overflow and process abort. No official SQLite release was verified vulnerable, and code execution was not demonstrated. The upstream change to `sqlite3_malloc64(sz)` is present in official SQLite 3.53.0 and removes the allocation-width mismatch.