From 98613139615c426d7c8e24846dd11477ccdd424d Mon Sep 17 00:00:00 2001 From: Dillard Blom Date: Wed, 30 Sep 2026 04:00:33 +0200 Subject: [PATCH] Treat DESCRIBE as a read DESCRIBE and DESC only show a table on MySQL/MariaDB. SQLite's PRAGMA stays out of the read list because it can also change settings. --- lib/Service/SqlGuard.php | 8 ++++++-- tests/Unit/Service/SqlGuardTest.php | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/Service/SqlGuard.php b/lib/Service/SqlGuard.php index 53a6368..ca7b3fe 100644 --- a/lib/Service/SqlGuard.php +++ b/lib/Service/SqlGuard.php @@ -32,8 +32,12 @@ class SqlGuard '/\bINTO\s+(OUTFILE|DUMPFILE)\b/i' => 'INTO OUTFILE/DUMPFILE', ]; - /** Statements that start with one of these only read, unless WRITES_INSIDE_READ matches. */ - private const READ_ONLY_START = '/^(SELECT|WITH|SHOW|EXPLAIN|SET|VALUES|TABLE)\b/i'; + /** + * Statements that start with one of these only read, unless + * WRITES_INSIDE_READ matches. SQLite's PRAGMA is left out on purpose: + * it can also change settings, so it asks for confirmation. + */ + private const READ_ONLY_START = '/^(SELECT|WITH|SHOW|EXPLAIN|DESCRIBE|DESC|SET|VALUES|TABLE)\b/i'; /** * What makes a statement that starts as a read change something: diff --git a/tests/Unit/Service/SqlGuardTest.php b/tests/Unit/Service/SqlGuardTest.php index 23caacc..eb850d1 100644 --- a/tests/Unit/Service/SqlGuardTest.php +++ b/tests/Unit/Service/SqlGuardTest.php @@ -74,6 +74,8 @@ class SqlGuardTest extends TestCase ["SELECT \$\$DELETE FROM x\$\$"], ["SELECT E'it\\'s delete' FROM t"], ['VALUES (1)'], + ['DESCRIBE oc_users'], + ['DESC oc_users'], ["SELECT '/* not a comment */' AS a, '-- nor this' AS b"], ]; } @@ -113,6 +115,7 @@ class SqlGuardTest extends TestCase ["SELECT nextval('seq')"], ['MERGE INTO t USING s ON true WHEN MATCHED THEN DELETE'], ['VACUUM'], + ['PRAGMA journal_mode = WAL'], ["WITH a AS (SELECT '/*'), b AS (DELETE FROM t RETURNING 1) SELECT '*/'"], ["SELECT '--' AS x FROM t WHERE a IN (SELECT 1) FOR UPDATE"], ["WITH a AS (SELECT \$\$/*\$\$), b AS (DELETE FROM t RETURNING 1) SELECT '*/'"],