From 66f69bb8881f5272632cf550359961952f09c06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20Ara=C3=BAjo?= Date: Fri, 16 Oct 2026 15:33:23 -0300 Subject: [PATCH] sqlite: validate backup() source is a DatabaseSync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backup() only checked that the source argument was a BaseObject before casting it to Database, so passing a Statement or Session caused a type confusion. Check against the DatabaseSync constructor template instead. Signed-off-by: Guilherme Araújo --- src/env_properties.h | 1 + src/node_sqlite.cc | 9 ++++++--- test/parallel/test-sqlite-backup.mjs | 18 +++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/env_properties.h b/src/env_properties.h index 087193faba98..c4e3bc5c72a0 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -451,6 +451,7 @@ V(socketaddress_constructor_template, v8::FunctionTemplate) \ V(space_stats_template, v8::DictionaryTemplate) \ V(sqlite_column_template, v8::DictionaryTemplate) \ + V(sqlite_database_constructor_template, v8::FunctionTemplate) \ V(sqlite_limits_template, v8::ObjectTemplate) \ V(sqlite_run_result_template, v8::DictionaryTemplate) \ V(sqlite_statement_sync_constructor_template, v8::FunctionTemplate) \ diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index b4fbfa88746a..e41d7390c07c 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -3208,9 +3208,11 @@ void Database::CreateSession(const FunctionCallbackInfo& args) { void Backup(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - if (args.Length() < 1 || !args[0]->IsObject()) { - THROW_ERR_INVALID_ARG_TYPE(env->isolate(), - "The \"sourceDb\" argument must be an object."); + if (!args[0]->IsObject() || + !env->sqlite_database_constructor_template()->HasInstance(args[0])) { + THROW_ERR_INVALID_ARG_TYPE( + env->isolate(), + "The \"sourceDb\" argument must be a DatabaseSync instance."); return; } @@ -5425,6 +5427,7 @@ static void Initialize(Local target, FIXED_ONE_BYTE_STRING(isolate, "node:sqlite"); db_tmpl->InstanceTemplate()->Set(sqlite_type_symbol, database_sync_string); + env->set_sqlite_database_constructor_template(db_tmpl); SetConstructorFunction(context, target, "Database", db_tmpl); SetConstructorFunction(context, target, diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs index cae097aa92ec..485076c04b93 100644 --- a/test/parallel/test-sqlite-backup.mjs +++ b/test/parallel/test-sqlite-backup.mjs @@ -48,10 +48,26 @@ describe('backup()', () => { backup(); }, { code: 'ERR_INVALID_ARG_TYPE', - message: 'The "sourceDb" argument must be an object.' + message: 'The "sourceDb" argument must be a DatabaseSync instance.' }); }); + test('throws if the source is not a DatabaseSync', (t) => { + const database = makeSourceDb(); + for (const source of [ + {}, + database.prepare('SELECT 1'), + database.createSession(), + ]) { + t.assert.throws(() => { + backup(source, 'out.db'); + }, { + code: 'ERR_INVALID_ARG_TYPE', + message: 'The "sourceDb" argument must be a DatabaseSync instance.' + }); + } + }); + test('throws if path is not a string, URL, or Buffer', (t) => { const database = makeSourceDb();