diff --git a/src/Codeception/Command/Console.php b/src/Codeception/Command/Console.php
index a124de459c..1d95cca00e 100644
--- a/src/Codeception/Command/Console.php
+++ b/src/Codeception/Command/Console.php
@@ -54,9 +54,19 @@ public function getDescription()
public function execute(InputInterface $input, OutputInterface $output)
{
$suiteName = $input->getArgument('suite');
- $this->output = $output;
+ // Validate suite name before using it
+ if (!preg_match('/^[a-zA-Z0-9_]+$/', $suiteName)) {
+ $output->writeln("Invalid suite name.");
+ return;
+ }
- $config = Configuration::config($input->getOption('config'));
+ $this->output = $output;
+ $configPath = $input->getOption('config');
+ if ($configPath && !preg_match('/^[a-zA-Z0-9_\-\/\.]+$/', $configPath)) {
+ $output->writeln("Invalid config file path.");
+ return;
+ }
+ $config = Configuration::config($configPath);
$settings = Configuration::suiteSettings($suiteName, $config);
$options = $input->getOptions();
@@ -112,8 +122,13 @@ protected function executeCommands(InputInterface $input, OutputInterface $outpu
{
$dialog = new QuestionHelper();
- if (file_exists($bootstrap)) {
- require $bootstrap;
+ $projectRoot = realpath(__DIR__ . '/../../../');
+ $bootstrapPath = realpath($bootstrap);
+
+ if ($bootstrapPath && strpos($bootstrapPath, $projectRoot) === 0 && file_exists($bootstrapPath)) {
+ require $bootstrapPath;
+ } else {
+ $output->writeln("Invalid bootstrap file path.");
}
do {
diff --git a/src/Codeception/Command/Shared/Config.php b/src/Codeception/Command/Shared/Config.php
index 64c59ab483..7d389ae38e 100644
--- a/src/Codeception/Command/Shared/Config.php
+++ b/src/Codeception/Command/Shared/Config.php
@@ -6,6 +6,13 @@ trait Config
{
protected function getSuiteConfig($suite, $conf)
{
+ // Allow only alphanumeric, underscore, and dash
+ if (!preg_match('/^[\w\-]+$/', $suite)) {
+ throw new \InvalidArgumentException("Invalid suite name.");
+ }
+ if (!preg_match('/^[\w\-\.\/]+$/', $conf)) {
+ throw new \InvalidArgumentException("Invalid config path.");
+ }
$config = Configuration::config($conf);
return Configuration::suiteSettings($suite, $config);
}
@@ -21,4 +28,4 @@ protected function getSuites($conf)
return Configuration::suites();
}
-}
\ No newline at end of file
+}
diff --git a/src/Codeception/Lib/Driver/PostgreSql.php b/src/Codeception/Lib/Driver/PostgreSql.php
index 07e7eb748d..0299591c00 100644
--- a/src/Codeception/Lib/Driver/PostgreSql.php
+++ b/src/Codeception/Lib/Driver/PostgreSql.php
@@ -45,22 +45,46 @@ public function load($sql)
public function cleanup()
{
+ // Get all tables in the public schema and generate DROP statements
$tables = $this->dbh
- ->query("SELECT 'DROP TABLE IF EXISTS \"' || tablename || '\" cascade;' FROM pg_tables WHERE schemaname = 'public';")
+ ->query("
+ SELECT 'DROP TABLE IF EXISTS ' || quote_ident(tablename) || ' CASCADE;'
+ FROM pg_tables
+ WHERE schemaname = 'public';
+ ")
->fetchAll();
+ // Get all sequences and generate DROP statements
$sequences = $this->dbh
- ->query("SELECT 'DROP SEQUENCE IF EXISTS \"' || relname || '\" cascade;' FROM pg_class WHERE relkind = 'S';")
+ ->query("
+ SELECT 'DROP SEQUENCE IF EXISTS ' || quote_ident(relname) || ' CASCADE;'
+ FROM pg_class
+ WHERE relkind = 'S';
+ ")
->fetchAll();
- $types = $this->dbh
- ->query("SELECT 'DROP TYPE IF EXISTS \"' || pg_type.typname || '\" cascade;' FROM pg_type JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid GROUP BY pg_type.typname;")
+ // Get all enum types and generate DROP statements
+ $types = $this->dbh
+ ->query("
+ SELECT 'DROP TYPE IF EXISTS ' || quote_ident(pg_type.typname) || ' CASCADE;'
+ FROM pg_type
+ JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid
+ GROUP BY pg_type.typname;
+ ")
->fetchAll();
+ // Merge all DROP statements into a single array
$drops = array_merge($tables, $sequences, $types);
+
+ // Execute each DROP statement safely
if ($drops) {
foreach ($drops as $drop) {
- $this->dbh->exec($drop[0]);
+ try {
+ $this->dbh->exec($drop[0]);
+ } catch (\PDOException $e) {
+ // Log the error but continue with the next DROP
+ error_log("Failed to execute: " . $drop[0] . " - " . $e->getMessage());
+ }
}
}
}