diff --git a/app/Helpers/SshMultiplexingHelper.php b/app/Helpers/SshMultiplexingHelper.php index cf92deb2a..021ac3608 100644 --- a/app/Helpers/SshMultiplexingHelper.php +++ b/app/Helpers/SshMultiplexingHelper.php @@ -63,10 +63,10 @@ class SshMultiplexingHelper $scpCommand .= self::getCommonSshOptions($server, $sshKeyLocation, self::getConnectionTimeout($server), config('constants.ssh.server_interval'), isScp: true); if ($server->isIpv6()) { - return $scpCommand."{$source} ".escapeshellarg($server->user).'@['.escapeshellarg($server->ip)."]:{$dest}"; + return $scpCommand.escapeshellarg($source).' '.escapeshellarg($server->user).'@['.escapeshellarg($server->ip).']:'.escapeshellarg($dest); } - return $scpCommand."{$source} ".self::escapedUserAtHost($server).":{$dest}"; + return $scpCommand.escapeshellarg($source).' '.self::escapedUserAtHost($server).':'.escapeshellarg($dest); } public static function generateSshCommand(Server $server, string $command, bool $disableMultiplexing = false): string diff --git a/tests/Unit/SshCommandInjectionTest.php b/tests/Unit/SshCommandInjectionTest.php index e7eeff62d..e7806b782 100644 --- a/tests/Unit/SshCommandInjectionTest.php +++ b/tests/Unit/SshCommandInjectionTest.php @@ -1,6 +1,7 @@ ip = '192.168.1.1;rm -rf /'; // Regex [^0-9a-zA-Z.:%-] removes ; space and /; hyphen is allowed expect($server->ip)->toBe('192.168.1.1rm-rf'); }); it('strips dangerous characters from server user on write', function () { - $server = new App\Models\Server; + $server = new Server; $server->user = 'root$(id)'; expect($server->user)->toBe('rootid'); }); it('strips non-numeric characters from server port on write', function () { - $server = new App\Models\Server; + $server = new Server; $server->port = '22; evil'; expect($server->port)->toBe(22); }); @@ -102,6 +103,17 @@ it('has no raw user@ip string interpolation in SshMultiplexingHelper', function expect($source)->not->toContain('{$server->user}@{$server->ip}'); }); +it('escapes scp source and destination operands', function () { + $reflection = new ReflectionClass(SshMultiplexingHelper::class); + $source = file_get_contents($reflection->getFileName()); + + expect($source) + ->toContain('escapeshellarg($source)') + ->toContain('escapeshellarg($dest)') + ->not->toContain('"{$source} "') + ->not->toContain('":{$dest}"'); +}); + // ------------------------------------------------------------------------- // ValidHostname rejects shell metacharacters // -------------------------------------------------------------------------