[TikiWiki-commits] [Git][tikiwiki/tiki][24.x] [BP][FIX] Fix critical command injection vulnerability in OpenPGP library
"Elifeleti Mukisa Dan \(@Danelif\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <6a1198bc8793b_381925d08128@gitlab-sidekiq-low-urgency-cpu-bound-v2-d7f87744c-dzzv2.mail> |
Elifeleti Mukisa Dan pushed to branch 24.x at Tiki Wiki CMS Groupware / Tiki Commits: 5b91c1ff by Elifeleti Mukisa Dan at 2026-05-23T12:03:00+00:00 [BP][FIX] Fix critical command injection vulnerability in OpenPGP library --- * [BP][FIX] Fix critical command injection vulnerability in OpenPGP library --- * [BP][FIX] Fix critical command injection vulnerability in OpenPGP library --- * [BP][FIX] Fix critical command injection vulnerability in OpenPGP library --- * [FIX] Fix critical command injection vulnerability in OpenPGP library --- * [FIX] Fix critical command injection vulnerability in OpenPGP library (cherry picked from commit 1657c46d2ba396765aca6ece6a988f55a962df22) 1657c46d [FIX] Fix critical command injection vulnerability in OpenPGP library Co-authored-by: Danelif <[email protected]> See merge request tikiwiki/tiki!10289 (cherry picked from commit ee9da8d5ec75de69a31c83a95980f79305fcb617) 5aabb286 [FIX] Fix critical command injection vulnerability in OpenPGP library Co-authored-by: Elifeleti Mukisa Dan <[email protected]> See merge request tikiwiki/tiki!10304 See merge request tikiwiki/tiki!10322 See merge request tikiwiki/tiki!10337 See merge request tikiwiki/tiki!10349 - - - - - 3 changed files: - lib/openpgp/OpenPGP_Zend_Mail_Transport_Sendmail.php - lib/openpgp/OpenPGP_Zend_Mail_Transport_Smtp.php - lib/openpgp/openpgplib.php Changes: ===================================== lib/openpgp/OpenPGP_Zend_Mail_Transport_Sendmail.php ===================================== @@ -67,7 +67,7 @@ class OpenPGP_Zend_Mail_Transport_Smtp extends Laminas\Mail\Transport\Sendmail } global $openpgplib; - $pgpmime_msg = $openpgplib->prepareEncryptWithZendMail($originalHeaders, $originalBody, $recipients); + $pgpmime_msg = $openpgplib->prepareEncryptWithZendMail($recipients, $originalHeaders, $originalBody); $headers = $pgpmime_msg[0]; // set pgp/mime headers from result array $this->OpenGPGStoreMailBody = $pgpmime_msg[1]; // set pgp/mime encrypted message body from result array ===================================== lib/openpgp/OpenPGP_Zend_Mail_Transport_Smtp.php ===================================== @@ -67,7 +67,7 @@ class OpenPGP_Zend_Mail_Transport_Smtp extends Laminas\Mail\Transport\Smtp } global $openpgplib; - $pgpmime_msg = $openpgplib->prepareEncryptWithZendMail($originalHeaders, $originalBody, $recipients); + $pgpmime_msg = $openpgplib->prepareEncryptWithZendMail($recipients, $originalHeaders, $originalBody); $headers = $pgpmime_msg[0]; // set pgp/mime headers from result array $this->OpenGPGStoreMailBody = $pgpmime_msg[1]; // set pgp/mime encrypted message body from result array ===================================== lib/openpgp/openpgplib.php ===================================== @@ -44,9 +44,10 @@ if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { exit; } +use Tiki\Process\Process; + class OpenPGPLib { - //PGP/MIME HEADER CONSTANTS const MULTIPART_PGP_ENCRYPTED = 'multipart/encrypted'; const TYPE_PGP_PROTOCOL = 'application/pgp-encrypted'; @@ -105,7 +106,7 @@ class OpenPGPLib * gpg trust * depending on which version of GnuPG we're using there * are two different ways to specify "always trust" - * @var string + * @var array * @access protected */ private $_gpg_trust; @@ -127,7 +128,7 @@ class OpenPGPLib $this->_gpg_sgn_passfile_path = ''; $this->_gpg_sgn_passphrase = $prefs['openpgp_gpg_signer_passphrase']; } - $this->_gpg_trust = ''; + $this->gpg_trust = []; $this->setCrlf(); } @@ -161,15 +162,13 @@ class OpenPGPLib /////////////////////////////// // open the GnuPG process and get the reply - // we're only concerned with the first line of output, so use "false" as last argument - $commandline = $this->_gpg_path - . ' --version'; - $ret = $this->_gpg_exec_proc($commandline, null, false); + // we're only concerned with the first line of output + $command = [$this->gpg_path, '--version']; + $ret = $this->gpgExecProc($command); ///////////////////////////////////////////////////// - // get the version (we are only concerned with the first line of output, - // which was read from gpg-process-output as single-line-read into $ret[1] - $gpg_version_output = $ret[0]; + // get the version (we are only concerned with the first line of output) + $gpg_version_output = strtok($ret[0], "\n"); /////////////////////////////////////////////// // sanity check - see if we're working with gpg @@ -191,17 +190,16 @@ class OpenPGPLib // depending on which version of GnuPG we're using there // are two different ways to specify "always trust" if ("$gpg_gpg_version" < '1.2.3') { - $this->_gpg_trust = '--always-trust'; // the old way + $this->gpg_trust = ['--always-trust']; // the old way } else { - $this->_gpg_trust = '--trust-model always'; // the new way + $this->gpg_trust = ['--trust-model', 'always']; // the new way } ///////////////////////////////////////////// // unset variables that we don't need anymore unset( $gpg_version_output, - $gpg_gpg_version, - $commandline + $gpg_gpg_version ); //////////////////////////////////////// @@ -213,102 +211,42 @@ class OpenPGPLib /** * Gnupg process call function * - * @param string $gpg_proc_call - * @param string $gpg_proc_input - * @param boolean $read_multilines + * @param array $command Array of command and arguments (no shell escaping needed) + * @param string $gpg_proc_input Optional input to send to GnuPG via STDIN * @access protected * @return array * 0 => process call output (STDOUT) * 1 => warnings and notices (STDERR) * 2 => exit status */ - protected function _gpg_exec_proc($gpg_proc_call = '', $gpg_proc_input = null, $read_multilines = true) + protected function gpgExecProc(array $command, $gpg_proc_input = null) { - - if ($gpg_proc_call == '') { + if (empty($command)) { die; } - ////////////////////////////////////////////// - // set up pipes for handling I/O to/from GnuPG - $gpg_descriptorspec = [ - 0 => ["pipe", "r"], // STDIN is a pipe that GnuPG will read from - 1 => ["pipe", "w"], // STDOUT is a pipe that GnuPG will write to - 2 => ["pipe", "w"] // STDERR is a pipe that GnuPG will write to - ]; - /////////////////////////////// // this opens the GnuPG process - $gpg_process = proc_open( - $gpg_proc_call, - $gpg_descriptorspec, - $gpg_pipes - ); + $process = new Process($command); ////////////////////////////////////////////////////////////////// - // this writes the "$gpg_encrypt_secret_message" to GnuPG on STDIN - if (is_resource($gpg_process)) { - if ($gpg_proc_input != null) { - fwrite($gpg_pipes[0], $gpg_proc_input); - } - fclose($gpg_pipes[0]); - - ///////////////////////////////////////////////////////// - // this reads the output from GnuPG from STDOUT - $gpg_proc_output = ''; - if ($read_multilines) { - while (! feof($gpg_pipes[1])) { - $gpg_proc_output .= fgets($gpg_pipes[1], 1024); - } - fclose($gpg_pipes[1]); - } else { - $gpg_proc_output = fgets($gpg_pipes[1], 1024); - } - - ///////////////////////////////////////////////////////// - // this reads warnings and notices from GnuPG from STDERR - $gpg_error_message = ''; - while (! feof($gpg_pipes[2])) { - $gpg_error_message .= fgets($gpg_pipes[2], 1024); - } - fclose($gpg_pipes[2]); - - ///////////////////////////////////////// - // this collects the exit status of GnuPG - $gpg_exit_status = proc_close($gpg_process); - - //////////////////////////////////////////// - // unset variables that are no longer needed - // and can only cause trouble - unset( - $gpg_descriptorspec, - $gpg_process, - $gpg_pipes - ); + // this writes the "$gpg_proc_input" to GnuPG on STDIN + if ($gpg_proc_input !== null) { + $process->setInput($gpg_proc_input); + } - //////////////////////////////////// - // this returns an array containing: - // [0] encrypted output (STDOUT) - // [1] warnings and notices (STDERR) - // [2] exit status - return [$gpg_proc_output, $gpg_error_message, $gpg_exit_status]; - } else { - //////////////////////////////////////////// - // unset variables that are no longer needed - // and can only cause trouble - unset( - $gpg_descriptorspec, - $gpg_process, - $gpg_pipes - ); + $process->run(); - ////////////////////////////// - // set output as otherwise nothing - $gpg_proc_output = ''; - $gpg_error_message = 'Fatal process call error: Process call failed!'; - $gpg_exit_status = 99; - return [$gpg_proc_output, $gpg_error_message, $gpg_exit_status]; - } + //////////////////////////////////// + // this returns an array containing: + // [0] encrypted output (STDOUT) + // [1] warnings and notices (STDERR) + // [2] exit status + return [ + $process->getOutput(), + $process->getErrorOutput(), + $process->getExitCode() + ]; } @@ -355,57 +293,52 @@ class OpenPGPLib /////////////////////////////////////////////////////////////////////// // make sure that each recipient has the message encrypted to their key // the 2nd argument, and any subsequent arguments, are key IDs - $gpg_recipient_list = ''; + $gpg_recipient_args = []; foreach ($gpg_args as $gpg_recipient) { if (is_array($gpg_recipient)) { - foreach ($gpg_recipient as &$item) { - $gpg_recipient_list .= ' -r ' . $item; + foreach ($gpg_recipient as $item) { + $gpg_recipient_args[] = '-r'; + $gpg_recipient_args[] = $item; } } else { - $gpg_recipient_list .= " -r ${gpg_recipient}"; + $gpg_recipient_args[] = '-r'; + $gpg_recipient_args[] = $gpg_recipient; } } ////////////////////////////////////////// // find which version of GnuPG we're using ////////////////////////////////////////// - if ($this->_gpg_trust == '') { - $this->_gpg_check_version(); + if (empty($this->gpg_trust)) { + $this->gpgCheckVersion(); } /////////////////////////////// // open the GnuPG process and get the reply - $commandline = ''; if ($prefs['openpgp_gpg_signer_passphrase_store'] == 'file') { // get signer-key passphrase from a file - $commandline .= $this->_gpg_path - . ' --no-random-seed-file' - . ' --homedir ' . $this->_gpg_home - . ' ' . $this->_gpg_trust - . ' --batch' - . ' --local-user ' . $this->_gpg_sgn_id - . ' --passphrase-file ' . $this->_gpg_sgn_passfile_path - . ' -sea ' . $gpg_recipient_list - . ' '; + $command = array_merge( + [$this->gpg_path, '--no-random-seed-file', '--homedir', $this->gpg_home], + $this->gpg_trust, + ['--batch', '--local-user', $this->gpg_sgn_id, '--passphrase-file', $this->gpg_sgn_passfile_path, '-sea'], + $gpg_recipient_args + ); } else { // get signer-key passphrase from preferences - $commandline .= $this->_gpg_path - . ' --no-random-seed-file' - . ' --homedir ' . $this->_gpg_home - . ' ' . $this->_gpg_trust - . ' --batch' - . ' --local-user ' . $this->_gpg_sgn_id - . ' --passphrase ' . $this->_gpg_sgn_passphrase - . ' -sea ' . $gpg_recipient_list - . ' '; + $command = array_merge( + [$this->gpg_path, '--no-random-seed-file', '--homedir', $this->gpg_home], + $this->gpg_trust, + ['--batch', '--local-user', $this->gpg_sgn_id, '--passphrase', $this->gpg_sgn_passphrase, '-sea'], + $gpg_recipient_args + ); } - $ret = $this->_gpg_exec_proc($commandline, $gpg_secret_message); + $ret = $this->gpgExecProc($command, $gpg_secret_message); unset( $gpg_args, $gpg_secret_message, - $gpg_recipient_list, - $commandline + $gpg_recipient_args, + $command ); //////////////////////////////////// @@ -459,23 +392,22 @@ class OpenPGPLib ////////////////////////////////////////// // find which version of GnuPG we're using ////////////////////////////////////////// - if ($this->_gpg_trust == '') { - $this->_gpg_check_version(); + if (empty($this->gpg_trust)) { + $this->gpgCheckVersion(); } /////////////////////////////// // open the GnuPG process and get the reply - $commandline = $this->_gpg_path - . ' --homedir ' . $this->_gpg_home - . ' ' . $this->_gpg_trust - . ' --fingerprint' - . ' --list-sigs ' . $gpg_key_id_to_return - . ' '; - $ret = $this->_gpg_exec_proc($commandline); + $command = array_merge( + [$this->gpg_path, '--homedir', $this->gpg_home], + $this->gpg_trust, + ['--fingerprint', '--list-sigs', $gpg_key_id_to_return] + ); + $ret = $this->gpgExecProc($command); unset( $gpg_key_id_to_return, - $commandline + $command ); //////////////////////////////////// @@ -529,22 +461,22 @@ class OpenPGPLib ////////////////////////////////////////// // find which version of GnuPG we're using ////////////////////////////////////////// - if ($this->_gpg_trust == '') { - $this->_gpg_check_version(); + if (empty($this->gpg_trust)) { + $this->gpgCheckVersion(); } /////////////////////////////// // open the GnuPG process and get the reply - $commandline = $this->_gpg_path - . ' --homedir ' . $this->_gpg_home - . ' ' . $this->_gpg_trust - . ' --export --armor ' . $gpg_key_id_to_return - . ' '; - $ret = $this->_gpg_exec_proc($commandline); + $command = array_merge( + [$this->gpg_path, '--homedir', $this->gpg_home], + $this->gpg_trust, + ['--export', '--armor', $gpg_key_id_to_return] + ); + $ret = $this->gpgExecProc($command); unset( $gpg_key_id_to_return, - $commandline + $command ); //////////////////////////////////// @@ -1139,7 +1071,7 @@ class OpenPGPLib * 0 => string $pgpmime_header * 1 => string $pgpmime_encrypted_message_body */ - public function prepareEncryptWithZendMail($original_mail_header = '', $original_mail_body = null, $recipients) + public function prepareEncryptWithZendMail($recipients, $original_mail_header = '', $original_mail_body = null) { // Define gnupg/mime header variables; see constants above in this class @@ -1233,6 +1165,7 @@ class OpenPGPLib // $gpg[1] warnings and notices (STDERR) // $gpg[2] exit status from gpg + // test gpg's exit status if ("$gpg[2]" == '0') { // if the gpg command returned zero View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5b91c1fff80d77d08b25db30836d14ea0285bbfc -- View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5b91c1fff80d77d08b25db30836d14ea0285bbfc You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help _______________________________________________ TikiWiki-cvs mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs