From 4c6b4298004d7ca941f6c84fee3867d04eda19bb Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 16 Jul 2026 14:08:28 +0000 Subject: [PATCH] sqlite: fix use-after-free in Exec() and ApplyChangeset() When sqlite3_exec() or sqlite3changeset_apply() call JavaScript callbacks (user-defined functions, conflict handlers, or filter callbacks), the DatabaseSync object could be garbage-collected if the JavaScript code drops all references to it. Both methods only held a raw DatabaseSync* pointer on the C++ stack, which V8 GC does not track. Add a BaseObjectPtr guard that keeps the database alive for the duration of these SQLite API calls, preventing a use-after-free when the JavaScript callback triggers GC. Signed-off-by: Matteo Collina --- src/node_sqlite.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index c3b7d279f4dca0..6428828b093a39 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -1584,6 +1584,13 @@ void DatabaseSync::Exec(const FunctionCallbackInfo& args) { return; } + // Keep the database alive during sqlite3_exec(), which may call + // user-defined SQLite functions that trigger JavaScript callbacks. + // If the JavaScript callback drops all references to the database, + // the DatabaseSync could otherwise be garbage-collected while the + // SQLite callback is still executing, causing a use-after-free. + BaseObjectPtr guard(db); + Utf8Value sql(env->isolate(), args[0].As()); int r = sqlite3_exec(db->connection_, *sql, nullptr, nullptr, nullptr); CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void()); @@ -2358,6 +2365,13 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo& args) { } } + // Keep the database alive during sqlite3changeset_apply(), which may + // call conflict or filter callbacks that trigger JavaScript execution. + // If the JavaScript callback drops all references to the database, + // the DatabaseSync could otherwise be garbage-collected while the + // callback is still executing, causing a use-after-free. + BaseObjectPtr guard(db); + ArrayBufferViewContents buf(args[0]); int r = sqlite3changeset_apply( db->connection_,