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 '*/'"],