SQLite
Summary
ExpandSQLite is a widely-deployed, self-contained embedded relational database engine implemented primarily in C, with binding layers for Java (JNI) and JavaScript (WebAssembly). The audited codebase spans the core B-tree storage engine, the session extension for changeset recording and application, the FTS3/FTS4 full-text search engine, a collection of loadable extensions and virtual tables in `ext/misc/`, the complete WASM/JS API layer including multiple Virtual File System implementations (OPFS, kvvfs, SAH Pool), JNI bindings with a layered Java API, and associated development tooling. The architecture reflects decades of iterative hardening across a codebase that serves as infrastructure for countless applications — from mobile operating systems to web browsers — making the security properties of every layer consequential at enormous scale.
The codebase exhibits deeply integrated security mechanisms that treat database corruption as an expected adversarial input rather than an exceptional condition. The B-tree engine performs systematic corruption detection at every stage of page parsing, cell extraction, and tree balancing via `SQLITE_CORRUPT_PAGE` and `SQLITE_CORRUPT_BKPT` macros, propagating errors cleanly rather than permitting undefined behavior. SQL construction throughout the tooling and extension code consistently uses parameterized formatting with `%w` and `%Q` specifiers to prevent injection, while filesystem-accessing extensions are gated with `SQLITE_DIRECTONLY` to restrict execution context. The FTS3 subsystem employs defense-in-depth through `FTS_CORRUPT_VTAB` return paths, bounded expression tree depth via `SQLITE_FTS3_MAX_EXPR_DEPTH`, and padding buffers (`FTS3_NODE_PADDING`) to absorb boundary conditions. The JNI layer leverages `SQLITE_ENABLE_API_ARMOR` to prevent null-pointer dereferences at the native boundary, while the WASM API enforces origin-scoped storage isolation and validates cross-boundary message types through explicit property checks.
The overall security posture of the SQLite codebase is exceptionally strong, consistent with a project that has undergone continuous fuzzing via OSS-Fuzz and formal verification efforts. Three findings at low-severity or above were identified across the entire audit scope. The most significant is finding [H-1], an integer overflow in the FTS3/FTS4 `fts4aux` virtual table's doclist parser where a corrupt FTS index can bypass an array bounds check and produce a heap out-of-bounds write — a realistic attack vector for applications that open untrusted SQLite database files. Two low-severity issues were identified: [M-1], a logic bug in `sessionChangesetExtendRecord` that uses an incorrect column accessor for float-typed default values during changegroup schema extension, and [M-2], an unbounded `strlen` on untrusted changeset data in `fuzzParseHeader` that can be exploited via crafted input. These findings are narrow in scope and addressable with minimal, targeted fixes, and they do not diminish the overall maturity of the project's security engineering.
Findings
3 issues identified
Integer Overflow in fts3aux Column Number Parsing Leads to Heap OOB Write
fts3_aux.c:217
View Details
Description
In fts3auxNextMethod state 3, a column number varint (64-bit) is cast to int and used to compute iCol+2 for array sizing. When iCol is near INT_MAX, iCol+2 overflows to negative, bypassing fts3auxGrowStatArray’s size check, then pCsr->aStat[iCol+1] performs a heap out-of-bounds write.
Impact
A crafted corrupt FTS3 database can trigger a heap buffer overflow when fts4aux is queried. This can lead to arbitrary code execution or denial of service in any application opening untrusted SQLite databases.
Recommendation
Add an upper bounds check on the column number value before the iCol+2 computation to prevent signed integer overflow.
Fix
The added check v>0x7FFFFFFD ensures that iCol+2 cannot overflow a signed 32-bit integer. Using the original 64-bit value v avoids implementation-defined behavior from casting out-of-range values to int. The constant 0x7FFFFFFD (INT_MAX-1) guarantees iCol+2 stays within int bounds.
ext/fts3/fts3_aux.c
Incorrect Column Accessor Produces Wrong Float Default Values
ext/session/sqlite3session.c
View Details
Description
In sessionChangesetExtendRecord, the SQLITE_FLOAT case calls sqlite3_column_int64() instead of sqlite3_column_double(). The returned integer is implicitly converted to double (losing fractional precision), then its IEEE 754 bit pattern is stored via memcpy. This produces incorrect serialized float values in extended changeset records.
Impact
Silent data corruption when using sqlite3changegroup_schema() to combine changesets with differing column counts where newer columns have floating-point default values. The default value is truncated to its integer part.
Recommendation
Replace sqlite3_column_int64 with sqlite3_column_double for the SQLITE_FLOAT case in sessionChangesetExtendRecord.
Fix
Using sqlite3_column_double correctly retrieves the floating-point value from the default-values statement, preserving fractional precision when serializing the extended record.
ext/session/sqlite3session.c
Unbounded strlen on Untrusted Changeset Data in fuzzParseHeader
ext/session/changesetfuzz.c
View Details
Description
fuzzParseHeader calls strlen() on a pointer into the changeset buffer to locate the nul-terminated table name. If the changeset is malformed and contains no nul byte before the end of the buffer, strlen reads past the allocated buffer. The bounds check (p>=pEnd) occurs after the overread.
Impact
Processing a crafted changeset file causes a heap buffer overread, potentially crashing the process or leaking adjacent heap memory. The changesetfuzz tool is designed to process untrusted changeset files.
Recommendation
Replace the unbounded strlen with a bounded scan that checks against pEnd before advancing.
Fix
The bounded scan iterates only within the valid buffer range [p, pEnd), preventing overreads on malformed input that lacks a nul terminator.
ext/session/changesetfuzz.c
Conclusion
ExpandThe SQLite codebase demonstrates a level of security maturity that reflects its position as one of the most widely-deployed software libraries in existence. Code quality is consistently high across all audited sections — from the core B-tree engine’s meticulous page validation and mutex ordering protocols, through the FTS3 extension’s systematic corruption detection in segment readers and doclist parsers, to the WASM API’s careful bridging of synchronous C-level VFS interfaces with asynchronous browser APIs. The defensive coding patterns are not superficial; they are structural, with corruption handling woven into the fundamental data access paths rather than bolted on as boundary checks. The session extension’s streaming input infrastructure, the shared-cache deadlock prevention via ascending-address lock ordering, and the backup API’s page-level reference counting all reflect a security-first engineering culture that prioritizes correctness over convenience.
The most pressing security concern is [H-1], the heap buffer out-of-bounds write in the FTS3/FTS4 fts4aux doclist parser, which can be triggered by opening and querying a crafted database file containing a corrupt FTS index. While exploitation requires the victim application to process an untrusted database — a scenario that is explicitly within SQLite’s threat model — the fix is minimal, requiring a single additional bounds check on the column number value before computing an array index. The two low-severity findings affect distinct subsystems: [M-1] concerns an incorrect column accessor in sessionChangesetExtendRecord that can silently produce wrong default values for floating-point columns when combining changesets with differing column counts, a subtle bug that could corrupt application data in schema-evolution workflows without triggering any error, while [M-2] identifies an unbounded string length computation on untrusted changeset data that could be leveraged to read beyond allocated buffer boundaries.
The codebase is suitable for continued production deployment. The three identified fixes are narrowly scoped and should be applied promptly — [H-1] to eliminate a memory corruption vector, and [M-1] and [M-2] to preserve data integrity and memory safety guarantees in changeset operations. Several files were truncated during analysis, including fts3.c, btree.c, sqlite3-wasm.c, sqlite3_rsync.c, and shathree.c; a follow-up review of these files in their entirety is recommended to achieve complete coverage. Cross-boundary invariants between the B-tree engine, pager, and VDBE — particularly around page cache coherency during concurrent backup operations and pointer-map consistency during auto-vacuum — should be verified in a subsequent integrated analysis pass.
On-Chain Verification
Compare these values with the on-chain attestation
Verify: download the markdown and compare the hash
sha256sum sqlite.md
Legal Disclaimer: This report covers the code submitted for analysis. It does not account for infrastructure, deployment configuration, third-party dependencies, or changes made after the audit date. Automated analysis may produce false positives or miss context-dependent vulnerabilities. audited.xyz provides this report “as is” without warranty of any kind.