mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-19 12:16:21 +00:00
fix: enhance security by validating and escaping database names, file paths, and proxy configuration filenames to prevent command injection
This commit is contained in:
1 parent
e60e74ac90
commit
0073d045fb
11 files changed
+439
-32
No files matched your search
@@ -107,6 +107,15 @@ class BackupEdit extends Component
|
||||
$this->backup->save_s3 = $this->saveS3;
|
||||
$this->backup->disable_local_backup = $this->disableLocalBackup;
|
||||
$this->backup->s3_storage_id = $this->s3StorageId;
|
||||
|
||||
// Validate databases_to_backup to prevent command injection
|
||||
if (filled($this->databasesToBackup)) {
|
||||
$databases = str($this->databasesToBackup)->explode(',');
|
||||
foreach ($databases as $db) {
|
||||
validateShellSafePath(trim($db), 'database name');
|
||||
}
|
||||
}
|
||||
|
||||
$this->backup->databases_to_backup = $this->databasesToBackup;
|
||||
$this->backup->dump_all = $this->dumpAll;
|
||||
$this->backup->timeout = $this->timeout;
|
||||
|
||||
@@ -328,12 +328,15 @@ class General extends Component
|
||||
$configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
|
||||
if ($oldScript && $oldScript['filename'] !== $script['filename']) {
|
||||
$old_file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$oldScript['filename']}";
|
||||
$delete_command = "rm -f $old_file_path";
|
||||
try {
|
||||
// Validate and escape filename to prevent command injection
|
||||
validateShellSafePath($oldScript['filename'], 'init script filename');
|
||||
$old_file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$oldScript['filename']}";
|
||||
$escapedOldPath = escapeshellarg($old_file_path);
|
||||
$delete_command = "rm -f {$escapedOldPath}";
|
||||
instant_remote_process([$delete_command], $this->server);
|
||||
} catch (Exception $e) {
|
||||
$this->dispatch('error', 'Failed to remove old init script from server: '.$e->getMessage());
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -370,13 +373,17 @@ class General extends Component
|
||||
if ($found) {
|
||||
$container_name = $this->database->uuid;
|
||||
$configuration_dir = database_configuration_dir().'/'.$container_name;
|
||||
$file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$script['filename']}";
|
||||
|
||||
$command = "rm -f $file_path";
|
||||
try {
|
||||
// Validate and escape filename to prevent command injection
|
||||
validateShellSafePath($script['filename'], 'init script filename');
|
||||
$file_path = "$configuration_dir/docker-entrypoint-initdb.d/{$script['filename']}";
|
||||
$escapedPath = escapeshellarg($file_path);
|
||||
|
||||
$command = "rm -f {$escapedPath}";
|
||||
instant_remote_process([$command], $this->server);
|
||||
} catch (Exception $e) {
|
||||
$this->dispatch('error', 'Failed to remove init script from server: '.$e->getMessage());
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -405,6 +412,16 @@ class General extends Component
|
||||
'new_filename' => 'required|string',
|
||||
'new_content' => 'required|string',
|
||||
]);
|
||||
|
||||
try {
|
||||
// Validate filename to prevent command injection
|
||||
validateShellSafePath($this->new_filename, 'init script filename');
|
||||
} catch (Exception $e) {
|
||||
$this->dispatch('error', $e->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$found = collect($this->initScripts)->firstWhere('filename', $this->new_filename);
|
||||
if ($found) {
|
||||
$this->dispatch('error', 'Filename already exists.');
|
||||
|
||||
@@ -179,6 +179,10 @@ class Storage extends Component
|
||||
$this->file_storage_directory_destination = trim($this->file_storage_directory_destination);
|
||||
$this->file_storage_directory_destination = str($this->file_storage_directory_destination)->start('/')->value();
|
||||
|
||||
// Validate paths to prevent command injection
|
||||
validateShellSafePath($this->file_storage_directory_source, 'storage source path');
|
||||
validateShellSafePath($this->file_storage_directory_destination, 'storage destination path');
|
||||
|
||||
\App\Models\LocalFileVolume::create([
|
||||
'fs_path' => $this->file_storage_directory_source,
|
||||
'mount_path' => $this->file_storage_directory_destination,
|
||||
|
||||
@@ -26,12 +26,19 @@ class DynamicConfigurationNavbar extends Component
|
||||
$proxy_path = $this->server->proxyPath();
|
||||
$proxy_type = $this->server->proxyType();
|
||||
$file = str_replace('|', '.', $fileName);
|
||||
|
||||
// Validate filename to prevent command injection
|
||||
validateShellSafePath($file, 'proxy configuration filename');
|
||||
|
||||
if ($proxy_type === 'CADDY' && $file === 'Caddyfile') {
|
||||
$this->dispatch('error', 'Cannot delete Caddyfile.');
|
||||
|
||||
return;
|
||||
}
|
||||
instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $this->server);
|
||||
|
||||
$fullPath = "{$proxy_path}/dynamic/{$file}";
|
||||
$escapedPath = escapeshellarg($fullPath);
|
||||
instant_remote_process(["rm -f {$escapedPath}"], $this->server);
|
||||
if ($proxy_type === 'CADDY') {
|
||||
$this->server->reloadCaddy();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@ class NewDynamicConfiguration extends Component
|
||||
'fileName' => 'required',
|
||||
'value' => 'required',
|
||||
]);
|
||||
|
||||
// Validate filename to prevent command injection
|
||||
validateShellSafePath($this->fileName, 'proxy configuration filename');
|
||||
|
||||
if (data_get($this->parameters, 'server_uuid')) {
|
||||
$this->server = Server::ownedByCurrentTeam()->whereUuid(data_get($this->parameters, 'server_uuid'))->first();
|
||||
}
|
||||
@@ -65,8 +69,10 @@ class NewDynamicConfiguration extends Component
|
||||
}
|
||||
$proxy_path = $this->server->proxyPath();
|
||||
$file = "{$proxy_path}/dynamic/{$this->fileName}";
|
||||
$escapedFile = escapeshellarg($file);
|
||||
|
||||
if ($this->newFile) {
|
||||
$exists = instant_remote_process(["test -f $file && echo 1 || echo 0"], $this->server);
|
||||
$exists = instant_remote_process(["test -f {$escapedFile} && echo 1 || echo 0"], $this->server);
|
||||
if ($exists == 1) {
|
||||
$this->dispatch('error', 'File already exists');
|
||||
|
||||
@@ -80,7 +86,7 @@ class NewDynamicConfiguration extends Component
|
||||
}
|
||||
$base64_value = base64_encode($this->value);
|
||||
instant_remote_process([
|
||||
"echo '{$base64_value}' | base64 -d | tee {$file} > /dev/null",
|
||||
"echo '{$base64_value}' | base64 -d | tee {$escapedFile} > /dev/null",
|
||||
], $this->server);
|
||||
if ($proxy_type === 'CADDY') {
|
||||
$this->server->reloadCaddy();
|
||||
|
||||
Reference in new issue
Block a user