diff --git a/util/Seeder/Migration/Databases/MariaDbImporter.cs b/util/Seeder/Migration/Databases/MariaDbImporter.cs index 3621382334..a04f7dda69 100644 --- a/util/Seeder/Migration/Databases/MariaDbImporter.cs +++ b/util/Seeder/Migration/Databases/MariaDbImporter.cs @@ -128,7 +128,12 @@ public class MariaDbImporter(DatabaseConfig config, ILogger log using var reader = command.ExecuteReader(); while (reader.Read()) { - columns.Add(reader.GetString(0)); + var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + + columns.Add(colName); } return columns; diff --git a/util/Seeder/Migration/Databases/PostgresImporter.cs b/util/Seeder/Migration/Databases/PostgresImporter.cs index 18f4b0e846..8b485fc7dd 100644 --- a/util/Seeder/Migration/Databases/PostgresImporter.cs +++ b/util/Seeder/Migration/Databases/PostgresImporter.cs @@ -127,7 +127,12 @@ public class PostgresImporter(DatabaseConfig config, ILogger l using var reader = command.ExecuteReader(); if (reader.Read()) { - return reader.GetString(0); + var actualTableName = reader.GetString(0); + + // Validate table name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(actualTableName, "table name"); + + return actualTableName; } return null; @@ -159,7 +164,12 @@ public class PostgresImporter(DatabaseConfig config, ILogger l using var reader = command.ExecuteReader(); while (reader.Read()) { - columns.Add(reader.GetString(0)); + var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + + columns.Add(colName); } return columns; @@ -190,7 +200,12 @@ public class PostgresImporter(DatabaseConfig config, ILogger l using var reader = command.ExecuteReader(); while (reader.Read()) { - columnTypes[reader.GetString(0)] = reader.GetString(1); + var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + + columnTypes[colName] = reader.GetString(1); } return columnTypes; diff --git a/util/Seeder/Migration/Databases/SqlServerExporter.cs b/util/Seeder/Migration/Databases/SqlServerExporter.cs index c711acea02..1061224178 100644 --- a/util/Seeder/Migration/Databases/SqlServerExporter.cs +++ b/util/Seeder/Migration/Databases/SqlServerExporter.cs @@ -92,7 +92,12 @@ public class SqlServerExporter(DatabaseConfig config, ILogger var tables = new List(); while (reader.Read()) { - tables.Add(reader.GetString(0)); + var tableName = reader.GetString(0); + + // Validate table name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(tableName, "table name"); + + tables.Add(tableName); } _logger.LogInformation("Discovered {Count} tables: {Tables}", tables.Count, string.Join(", ", tables)); @@ -143,6 +148,10 @@ public class SqlServerExporter(DatabaseConfig config, ILogger while (reader.Read()) { var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + var dataType = reader.GetString(1); var isNullable = reader.GetString(2); var maxLength = reader.IsDBNull(3) ? (int?)null : reader.GetInt32(3); diff --git a/util/Seeder/Migration/Databases/SqlServerImporter.cs b/util/Seeder/Migration/Databases/SqlServerImporter.cs index 506957d246..0799e88e3c 100644 --- a/util/Seeder/Migration/Databases/SqlServerImporter.cs +++ b/util/Seeder/Migration/Databases/SqlServerImporter.cs @@ -87,7 +87,12 @@ public class SqlServerImporter(DatabaseConfig config, ILogger using var reader = command.ExecuteReader(); while (reader.Read()) { - columns.Add(reader.GetString(0)); + var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + + columns.Add(colName); } return columns; @@ -123,7 +128,12 @@ public class SqlServerImporter(DatabaseConfig config, ILogger using var reader = command.ExecuteReader(); while (reader.Read()) { - columnTypes[reader.GetString(0)] = reader.GetString(1); + var colName = reader.GetString(0); + + // Validate column name immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(colName, "column name"); + + columnTypes[colName] = reader.GetString(1); } return columnTypes; @@ -274,11 +284,16 @@ public class SqlServerImporter(DatabaseConfig config, ILogger while (reader.Read()) { - constraints.Add(( - reader.GetString(0), - reader.GetString(1), - reader.GetString(2) - )); + var schema = reader.GetString(0); + var table = reader.GetString(1); + var constraint = reader.GetString(2); + + // Validate all identifiers immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(schema, "schema name"); + IdentifierValidator.ValidateOrThrow(table, "table name"); + IdentifierValidator.ValidateOrThrow(constraint, "constraint name"); + + constraints.Add((schema, table, constraint)); } _logger.LogDebug("Found {Count} constraints to re-enable from tracking table", constraints.Count); @@ -399,11 +414,16 @@ public class SqlServerImporter(DatabaseConfig config, ILogger { while (reader.Read()) { - constraints.Add(( - reader.GetString(0), - reader.GetString(1), - reader.GetString(2) - )); + var schema = reader.GetString(0); + var table = reader.GetString(1); + var constraint = reader.GetString(2); + + // Validate all identifiers immediately to prevent second-order SQL injection + IdentifierValidator.ValidateOrThrow(schema, "schema name"); + IdentifierValidator.ValidateOrThrow(table, "table name"); + IdentifierValidator.ValidateOrThrow(constraint, "constraint name"); + + constraints.Add((schema, table, constraint)); } }