Skip to content

Commit e9e20dc

Browse files
committed
security: fix SQL injection in fetchTableMetadata
- Escape single quotes in table names for PostgreSQL and SQLite - Use safeTableName.replacingOccurrences(of: "'", with: "''") to prevent injection
1 parent 9d7c043 commit e9e20dc

2 files changed

Lines changed: 10 additions & 4 deletions

File tree

OpenTable/Core/Database/PostgreSQLDriver.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ final class PostgreSQLDriver: DatabaseDriver {
311311
}
312312

313313
func fetchTableMetadata(tableName: String) async throws -> TableMetadata {
314+
// Escape table name to prevent SQL injection (double quotes for PostgreSQL identifiers)
315+
let safeTableName = tableName.replacingOccurrences(of: "\"", with: "\"\"")
316+
314317
let query = """
315318
SELECT
316319
pg_total_relation_size(c.oid) AS total_size,
@@ -321,7 +324,7 @@ final class PostgreSQLDriver: DatabaseDriver {
321324
obj_description(c.oid, 'pg_class') AS comment
322325
FROM pg_class c
323326
JOIN pg_namespace n ON n.oid = c.relnamespace
324-
WHERE c.relname = '\(tableName)'
327+
WHERE c.relname = '\(safeTableName.replacingOccurrences(of: "'", with: "''"))'
325328
AND n.nspname = 'public'
326329
"""
327330

OpenTable/Core/Database/SQLiteDriver.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,11 @@ final class SQLiteDriver: DatabaseDriver {
302302
throw DatabaseError.notConnected
303303
}
304304

305+
// Escape table name to prevent SQL injection
306+
let safeTableName = tableName.replacingOccurrences(of: "'", with: "''")
307+
305308
// Get row count
306-
let countQuery = "SELECT COUNT(*) FROM '\(tableName)'"
309+
let countQuery = "SELECT COUNT(*) FROM '\(safeTableName)'"
307310
let countResult = try await execute(query: countQuery)
308311
let rowCount: Int64? = {
309312
guard let row = countResult.rows.first, let countStr = row.first else { return nil }
@@ -317,13 +320,13 @@ final class SQLiteDriver: DatabaseDriver {
317320
let size = attrs[.size] as? Int64 else { return nil }
318321
return size
319322
}()
320-
323+
321324
// Estimate average row length
322325
let avgRowLength: Int64? = {
323326
guard let total = fileSize, let count = rowCount, count > 0 else { return nil }
324327
return total / count
325328
}()
326-
329+
327330
return TableMetadata(
328331
tableName: tableName,
329332
dataSize: fileSize,

0 commit comments

Comments
 (0)