From d97fb443339305406f5e5580c1a87c43e3e84799 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 29 Jun 2026 12:37:48 -0400 Subject: [PATCH 1/5] Add missing escaping to adapters Update query generation for reflection methods in adapter layers to mitigate potential sql injection. While phinx should never have user controlled data provided to it, security researchers don't know that. --- src/Phinx/Db/Adapter/MysqlAdapter.php | 4 ++-- src/Phinx/Db/Adapter/PostgresAdapter.php | 1 + src/Phinx/Db/Adapter/SqlServerAdapter.php | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Phinx/Db/Adapter/MysqlAdapter.php b/src/Phinx/Db/Adapter/MysqlAdapter.php index bc758f774..4009ddb9e 100644 --- a/src/Phinx/Db/Adapter/MysqlAdapter.php +++ b/src/Phinx/Db/Adapter/MysqlAdapter.php @@ -1419,8 +1419,8 @@ public function hasDatabase(string $name): bool { $rows = $this->fetchAll( sprintf( - 'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'', - $name, + 'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = %s', + $this->getConnection()->quote($name), ), ); diff --git a/src/Phinx/Db/Adapter/PostgresAdapter.php b/src/Phinx/Db/Adapter/PostgresAdapter.php index 9dc0fe431..25ae666a9 100644 --- a/src/Phinx/Db/Adapter/PostgresAdapter.php +++ b/src/Phinx/Db/Adapter/PostgresAdapter.php @@ -1206,6 +1206,7 @@ public function createDatabase(string $name, array $options = []): void */ public function hasDatabase(string $name): bool { + $name = $this->getConnection()->quote($name); $sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = '%s'", $name); $result = $this->fetchRow($sql); diff --git a/src/Phinx/Db/Adapter/SqlServerAdapter.php b/src/Phinx/Db/Adapter/SqlServerAdapter.php index 6a36f81cd..99a05712c 100644 --- a/src/Phinx/Db/Adapter/SqlServerAdapter.php +++ b/src/Phinx/Db/Adapter/SqlServerAdapter.php @@ -1198,8 +1198,8 @@ public function hasDatabase(string $name): bool /** @var array $result */ $result = $this->fetchRow( sprintf( - "SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = '%s'", - $name, + "SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = %s", + $this->getConnection()->quote($name), ), ); From 15a94eb31a2812ee3920b7c39742dad01c4476bf Mon Sep 17 00:00:00 2001 From: Matthew Peveler Date: Tue, 30 Jun 2026 04:25:13 +0000 Subject: [PATCH 2/5] Refactor SQL query in hasDatabase method --- src/Phinx/Db/Adapter/PostgresAdapter.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Phinx/Db/Adapter/PostgresAdapter.php b/src/Phinx/Db/Adapter/PostgresAdapter.php index 25ae666a9..008777195 100644 --- a/src/Phinx/Db/Adapter/PostgresAdapter.php +++ b/src/Phinx/Db/Adapter/PostgresAdapter.php @@ -1206,8 +1206,7 @@ public function createDatabase(string $name, array $options = []): void */ public function hasDatabase(string $name): bool { - $name = $this->getConnection()->quote($name); - $sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = '%s'", $name); + $sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = %s", $this->getConnection()->quote($name)); $result = $this->fetchRow($sql); return $result['count'] > 0; From d63a1f91a35bc2b6042fee601b3089c589b46041 Mon Sep 17 00:00:00 2001 From: Matthew Peveler Date: Mon, 29 Jun 2026 23:28:13 -0600 Subject: [PATCH 3/5] Fix SQL string quotes in hasDatabase method --- src/Phinx/Db/Adapter/PostgresAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Phinx/Db/Adapter/PostgresAdapter.php b/src/Phinx/Db/Adapter/PostgresAdapter.php index 008777195..9fb6c2daa 100644 --- a/src/Phinx/Db/Adapter/PostgresAdapter.php +++ b/src/Phinx/Db/Adapter/PostgresAdapter.php @@ -1206,7 +1206,7 @@ public function createDatabase(string $name, array $options = []): void */ public function hasDatabase(string $name): bool { - $sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = %s", $this->getConnection()->quote($name)); + $sql = sprintf('SELECT count(*) FROM pg_database WHERE datname = %s', $this->getConnection()->quote($name)); $result = $this->fetchRow($sql); return $result['count'] > 0; From a58d3975507d0a3c2641c5b3e28d01aa79212b1b Mon Sep 17 00:00:00 2001 From: Matthew Peveler Date: Mon, 29 Jun 2026 23:28:55 -0600 Subject: [PATCH 4/5] Fix string quotes in SQL query for SQL Server --- src/Phinx/Db/Adapter/SqlServerAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Phinx/Db/Adapter/SqlServerAdapter.php b/src/Phinx/Db/Adapter/SqlServerAdapter.php index 99a05712c..e730804b2 100644 --- a/src/Phinx/Db/Adapter/SqlServerAdapter.php +++ b/src/Phinx/Db/Adapter/SqlServerAdapter.php @@ -1198,7 +1198,7 @@ public function hasDatabase(string $name): bool /** @var array $result */ $result = $this->fetchRow( sprintf( - "SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = %s", + 'SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = %s', $this->getConnection()->quote($name), ), ); From 2cc391cf95e702d29c25b765aeb36e8ba86a1b26 Mon Sep 17 00:00:00 2001 From: Matthew Peveler Date: Tue, 30 Jun 2026 06:45:13 +0000 Subject: [PATCH 5/5] add tests Signed-off-by: Matthew Peveler --- tests/Phinx/Db/Adapter/MysqlAdapterTest.php | 5 +++++ tests/Phinx/Db/Adapter/PostgresAdapterTest.php | 5 +++++ tests/Phinx/Db/Adapter/SqlServerAdapterTest.php | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php index ccd7ab07a..a4e330a90 100644 --- a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php +++ b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php @@ -2030,6 +2030,11 @@ public function testHasDatabase() $this->assertTrue($this->adapter->hasDatabase(MYSQL_DB_CONFIG['name'])); } + public function testHasDatabaseWithSingleQuoteInName() + { + $this->assertFalse($this->adapter->hasDatabase("fake'database'name")); + } + public function testDropDatabase() { $this->assertFalse($this->adapter->hasDatabase('phinx_temp_database')); diff --git a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php index d1db27e39..c38200358 100644 --- a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php +++ b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php @@ -1949,6 +1949,11 @@ public function testHasDatabase() $this->assertTrue($this->adapter->hasDatabase(PGSQL_DB_CONFIG['name'])); } + public function testHasDatabaseWithSingleQuoteInName() + { + $this->assertFalse($this->adapter->hasDatabase("fake'database'name")); + } + public function testDropDatabase() { $this->assertFalse($this->adapter->hasDatabase('phinx_temp_database')); diff --git a/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php b/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php index a69fc96a1..024378262 100644 --- a/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php +++ b/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php @@ -1184,6 +1184,11 @@ public function testHasDatabase() $this->assertTrue($this->adapter->hasDatabase(SQLSRV_DB_CONFIG['name'])); } + public function testHasDatabaseWithSingleQuoteInName() + { + $this->assertFalse($this->adapter->hasDatabase("fake'database'name")); + } + public function testDropDatabase() { $this->assertFalse($this->adapter->hasDatabase('phinx_temp_database'));