mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-16 14:13:22 +00:00
fix(sentinel): add token validation to prevent command injection
Add validation to ensure sentinel tokens contain only safe characters (alphanumeric, dots, hyphens, underscores, plus, forward slash, equals), preventing OS command injection vulnerabilities when tokens are interpolated into shell commands. - Add ServerSetting::isValidSentinelToken() validation method - Validate tokens in StartSentinel action and metrics queries - Improve shell argument escaping with escapeshellarg() - Add comprehensive test coverage for token validation
This commit is contained in:
1 parent
6fbb5e626a
commit
096d4369e5
5 files changed
+118
-3
No files matched your search
@@ -4,6 +4,7 @@ namespace App\Actions\Server;
|
||||
|
||||
use App\Events\SentinelRestarted;
|
||||
use App\Models\Server;
|
||||
use App\Models\ServerSetting;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StartSentinel
|
||||
@@ -23,6 +24,9 @@ class StartSentinel
|
||||
$refreshRate = data_get($server, 'settings.sentinel_metrics_refresh_rate_seconds');
|
||||
$pushInterval = data_get($server, 'settings.sentinel_push_interval_seconds');
|
||||
$token = data_get($server, 'settings.sentinel_token');
|
||||
if (! ServerSetting::isValidSentinelToken($token)) {
|
||||
throw new \RuntimeException('Invalid sentinel token format. Token must contain only alphanumeric characters, dots, hyphens, and underscores.');
|
||||
}
|
||||
$endpoint = data_get($server, 'settings.sentinel_custom_url');
|
||||
$debug = data_get($server, 'settings.is_sentinel_debug_enabled');
|
||||
$mountDir = '/data/coolify/sentinel';
|
||||
@@ -49,7 +53,7 @@ class StartSentinel
|
||||
}
|
||||
$mountDir = '/var/lib/docker/volumes/coolify_dev_coolify_data/_data/sentinel';
|
||||
}
|
||||
$dockerEnvironments = '-e "'.implode('" -e "', array_map(fn ($key, $value) => "$key=$value", array_keys($environments), $environments)).'"';
|
||||
$dockerEnvironments = implode(' ', array_map(fn ($key, $value) => '-e '.escapeshellarg("$key=$value"), array_keys($environments), $environments));
|
||||
$dockerLabels = implode(' ', array_map(fn ($key, $value) => "$key=$value", array_keys($labels), $labels));
|
||||
$dockerCommand = "docker run -d $dockerEnvironments --name coolify-sentinel -v /var/run/docker.sock:/var/run/docker.sock -v $mountDir:/app/db --pid host --health-cmd \"curl --fail http://127.0.0.1:8888/api/health || exit 1\" --health-interval 10s --health-retries 3 --add-host=host.docker.internal:host-gateway --label $dockerLabels $image";
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class Sentinel extends Component
|
||||
|
||||
public bool $isMetricsEnabled;
|
||||
|
||||
#[Validate(['required'])]
|
||||
#[Validate(['required', 'string', 'max:500', 'regex:/\A[a-zA-Z0-9._\-+=\/]+\z/'])]
|
||||
public string $sentinelToken;
|
||||
|
||||
public ?string $sentinelUpdatedAt = null;
|
||||
|
||||
@@ -92,6 +92,15 @@ class ServerSetting extends Model
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a sentinel token contains only safe characters.
|
||||
* Prevents OS command injection when the token is interpolated into shell commands.
|
||||
*/
|
||||
public static function isValidSentinelToken(string $token): bool
|
||||
{
|
||||
return (bool) preg_match('/\A[a-zA-Z0-9._\-+=\/]+\z/', $token);
|
||||
}
|
||||
|
||||
public function generateSentinelToken(bool $save = true, bool $ignoreEvent = false)
|
||||
{
|
||||
$data = [
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
use App\Models\ServerSetting;
|
||||
|
||||
trait HasMetrics
|
||||
{
|
||||
public function getCpuMetrics(int $mins = 5): ?array
|
||||
@@ -26,8 +28,13 @@ trait HasMetrics
|
||||
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
||||
$endpoint = $this->getMetricsEndpoint($type, $from);
|
||||
|
||||
$token = $server->settings->sentinel_token;
|
||||
if (! ServerSetting::isValidSentinelToken($token)) {
|
||||
throw new \Exception('Invalid sentinel token format. Please regenerate the token.');
|
||||
}
|
||||
|
||||
$response = instant_remote_process(
|
||||
["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$server->settings->sentinel_token}\" {$endpoint}'"],
|
||||
["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$token}\" {$endpoint}'"],
|
||||
$server,
|
||||
false
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user