Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion ProcessMaker/Console/Commands/BuildScriptExecutors.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ class BuildScriptExecutors extends Command
*
* @var string
*/
protected $signature = 'processmaker:build-script-executor {lang} {user?} {--rebuild}';
protected $signature = 'processmaker:build-script-executor
{lang : The ID or language of the script executor}
{user? : The user ID to send the broadcast event to}
{--rebuild : Rebuild the docker image}
{--build-args= : The build arguments for the docker build command}';

/**
* The console command description.
Expand Down Expand Up @@ -159,6 +163,12 @@ public function buildExecutor()
$command = Docker::command() .
" build --build-arg SDK_DIR=./sdk -t {$image} -f {$packagePath}/Dockerfile.custom {$packagePath}";

$buildArgs = $this->getBuildArgs();

foreach ($buildArgs as $buildArg) {
$command .= ' ' . $buildArg;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build args appended after docker build context path

Medium Severity

The --build-arg options from getBuildArgs() are appended after the build context path {$packagePath} in the docker build command. Docker build syntax requires all options to precede the PATH argument (docker build [OPTIONS] PATH). The resulting command places --build-arg values after the context path, which means the new --build-args feature will not work correctly as Docker expects the build context to be the final argument.

Fix in Cursor Fix in Web


$this->execCommand($command);

$isNayra = $scriptExecutor->language === Base::NAYRA_LANG;
Expand All @@ -167,6 +177,29 @@ public function buildExecutor()
}
}

/**
* Get the build arguments for the docker build command.
*
* @return array
* - '--build-arg <key>=<value>'
*/
public function getBuildArgs(): array
{
$args = $this->option('build-args');

if ($args) {
$buildArgs = [];

foreach (explode(',', $args) as $arg) {
$buildArgs[] = '--build-arg ' . $arg;
}

return $buildArgs;
}

return [];
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shell command injection via unsanitized build-args input

High Severity

The getBuildArgs() method constructs shell command arguments by directly concatenating user-supplied input from the --build-args option without escaping. The value is split by comma and each part is appended as --build-arg $arg to the Docker command, which is then passed to system() or proc_open(). An attacker could inject arbitrary shell commands (e.g., --build-args="FOO=bar; malicious-command"). The codebase uses escapeshellarg() elsewhere for this purpose, such as in ScriptRunners/Base.php and TenantsCreate.php.

🔬 Verification Test

Why verification test was not possible: This is a shell command injection vulnerability that would require actually running the artisan command with malicious input against a Docker environment. Running such a test could cause unintended system changes. However, the vulnerability is evident from code inspection: the $arg variable from user input is directly concatenated into a shell command string ('--build-arg ' . $arg) without any call to escapeshellarg(), and this string is ultimately passed to system() or proc_open(). The pattern used elsewhere in the codebase (e.g., escapeshellarg() in Base.php lines 88, 181, 190) demonstrates the expected sanitization that is missing here.

Additional Locations (1)

Fix in Cursor Fix in Web


public function getDockerfileContent(ScriptExecutor $scriptExecutor): string
{
$lang = $scriptExecutor->language;
Expand Down
15 changes: 11 additions & 4 deletions ProcessMaker/Models/ScriptDockerNayraTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ trait ScriptDockerNayraTrait
{

private $schema = 'http';
public static $nayraPort = 8080;

/**
* Execute the script task using Nayra Docker.
Expand Down Expand Up @@ -82,7 +81,7 @@ public function handleNayraDocker(string $code, array $data, array $config, $tim
private function getNayraInstanceUrl()
{
$servers = self::getNayraAddresses();
return $this->schema . '://' . $servers[0] . ':' . static::$nayraPort;
return $this->schema . '://' . $servers[0] . ':' . $this->getNayraPort();
}

private function getDockerLogs($instanceName)
Expand Down Expand Up @@ -131,11 +130,14 @@ private function bringUpNayra($restart = false)
if ($status) {
$this->bringUpNayraContainer();
} else {

$isHost = config('app.nayra_docker_network') === 'host';
$portMapping = $isHost ? '-e PORT=' . $this->getNayraPort() . ' ' : '-p ' . $this->getNayraPort() . ':8080 ';
exec($docker . " stop {$instanceName}_nayra 2>&1 || true");
exec($docker . " rm {$instanceName}_nayra 2>&1 || true");
exec(
$docker . ' run -d --name ' . $instanceName . '_nayra '
$docker . ' run -d '
. ($this->getNayraPort() !== 8080 ? $portMapping : '')
. '--name ' . $instanceName . '_nayra '
. (config('app.nayra_docker_network')
? '--network=' . config('app.nayra_docker_network') . ' '
: '')
Expand Down Expand Up @@ -322,4 +324,9 @@ public static function initNayraPhpUnitTest()
}
}
}

private function getNayraPort()
{
return config('app.nayra_port', 8080);
}
}
1 change: 1 addition & 0 deletions config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@
'force_https' => env('FORCE_HTTPS', true),

'nayra_docker_network' => env('NAYRA_DOCKER_NETWORK', 'host'),
'nayra_port' => env('NAYRA_PORT', 8080),

// Process Request security log rate limit: 1 per day (86400 seconds)
'process_request_errors_rate_limit' => env('PROCESS_REQUEST_ERRORS_RATE_LIMIT', 1),
Expand Down
Loading